Вступление
В этой статье мы увидим, как использовать MongoDB, нереляционную базу данных, с Django, веб-платформой Python.
Django обычно используется с PostgreSQL, MariaDB или MySQL, всеми реляционными базами данных, из-за того, что под капотом находится ORM. MongoDB, будучи довольно гибким, обычно сочетается с легкими фреймворками, такими как Flask, для упрощения прототипирования. Однако он также все чаще используется в более крупных проектах из-за масштабируемости, динамических структур и поддержки запросов.
Django MongoDB Engine используется для декларативного определения схем.
Примечание. На момент написания этот движок не поддерживает Python 3.x. Последняя поддерживаемая версия - Python 2.7 .
Нереляционные и реляционные базы данных
Ключевым отличием этого движка от других популярных движков является то, что он работает с нереляционной базой данных, тогда как приложения Django чаще разрабатываются с реляционными базами данных.
Выбор между этими двумя подходами сводится к проекту, над которым вы работаете, поскольку у каждого типа есть определенные плюсы и минусы в зависимости от ситуации. Нереляционные базы данных обычно более гибкие (как за, так и против), в то время как реляционные базы данных более согласованы (также как за, так и против).
Нереляционные базы данных также обычно лучше подходят для масштабируемых систем, в которых хранится много данных . Однако для малых и средних систем часто преобладает простота обслуживания реляционных баз данных.
Реляционная база данных
Реляционная база данных хранит данные в таблицах, которые состоят из столбцов и строк.
- Строка представляет объект (например,
Movie
) - Столбец представляет атрибут объекта (например,
name
фильма, егоlength
,year
выпуска и т. Д.) - Строка представляет одну запись в базе данных (например,
{"The Matrix", 2h 16min, 1999.}
).
Каждая строка таблицы должна иметь уникальный ключ ( идентификатор ), который представляет только эту строку.
Некоторые из самых известных реляционных баз данных: Oracle, PostgreSQL, MySQL и MariaDB .
Нереляционная база данных
Нереляционная база данных не хранит данные в таблицах, это зависит от типа данных. Существует четыре различных типа нереляционных баз данных:
- Документно-ориентированная база данных (или хранилище документов)
- Управляет набором именованных строковых полей, обычно в форме документов JSON, XML или YAML. Эти форматы также могут иметь производные.
- Магазин ширококолонный
- Организует данные в столбцы по структуре, аналогичной реляционным базам данных.
- Магазин Graph
- Хранит отношения между сущностями (самый сложный тип нереляционной базы данных)
- Используется, когда данные широко взаимосвязаны
- Хранилище ключей и значений
- Простая коллекция пар "ключ-значение"
Некоторые из самых известных нереляционных баз данных: MongoDB, Cassandra, Redis .
{.ezlazyload}
MongoDB является документ , на основе не-реляционная база данных, которая сохраняет документы в формате BSON (Binary JSON) - это производная JSON.
Установка и настройка
Чтобы реализовать Django MongoDB Engine в проекте, нам нужно установить три вещи:
- Django-nonrel - Поддержка нереляционных баз данных (при этом также будет установлен Django 1.5 и удалена любая ранее установленная версия).
- djangotoolbox - Инструменты для нереляционных приложений Django.
- Django MongoDB Engine - сам движок.
Давайте установим их через pip
вместе с самим Django:
$ pip install django
$ pip install git+https://github.com/django-nonrel/ [email protected]
$ pip install git+https://github.com/django-nonrel/djangotoolbox
$ pip install git+https://github.com/django-nonrel/mongodb-engine
Давайте инициализируем проект Django через командную строку, чтобы получить отправную точку:
$ django-admin.py startproject djangomongodbengine
Теперь, имея скелетный проект, содержащий некоторые базовые файлы, мы
хотим сообщить Django, какой движок мы хотим использовать. Для этого мы
обновим наш settings.py
и, в частности, свойство DATABASES
DATABASES = {
'default' : {
'ENGINE' : 'django_mongodb_engine',
'NAME' : 'example_database'
}
}
После завершения установки и настройки давайте взглянем на некоторые вещи, которые мы можем делать с помощью Django MongoDB Engine.
Модели и поля
Когда дело доходит до работы с моделями , в стандартной архитектуре
MVC (модель-представление-контроллер) классический подход заключается в
использовании модуля django.db.models
Класс Model
имеет CharField
s, TextField
s и т. Д., Которые позволяют вам по существу определять
схему ваших моделей и то, как они будут отображаться в базе данных ORM
Django.
Давайте добавим Movie
в наш models.py
:
from django.db import models
class Movie(models.Model)
name = models.CharField()
length = models.IntegerField()
Здесь у нас есть Movie
с двумя полями - name
и length
. Каждый из
них является Field
, представляющего столбец базы данных с заданным
типом данных.
Хотя существует довольно много типов
полей
, models
не имеет большой поддержки для полей с несколькими
значениями.
В основном это связано с тем, что models
предназначен в основном для
использования с реляционными базами данных. Когда у объекта есть поле с
несколькими значениями, например Movie
имеющий много Actor
s, у вас
будет связь « один ко многим» с другой таблицей.
С MongoDB вы можете сохранить их в виде списка в этом документе без
необходимости делать ссылку базы данных на другую таблицу или документ.
Именно здесь мы чувствуем нехватку таких полей, как ListField
и
DictField
.
ListField
ListField
- это атрибут типа списка, атрибут, который может содержать
несколько значений. Он принадлежит djangotoolbox.fields
и может
использоваться для указания полей, содержащих значения в виде списка,
которые затем сохраняются в документе BSON.
Давайте настроим нашу Movie
из предыдущего:
from django.db import models
from djangotoolbox.fields import ListField
class Movie(models.Model):
name = models.CharField()
length = models.IntegerField()
year = models.IntegerField()
actors = ListField()
Обратите внимание, что мы не указали поле id
В этом нет необходимости,
поскольку MongoDB неявно назначит его экземпляру Model
. Кроме того,
мы добавили actors
, которое является ListField
.
Теперь при создании Movie
мы можем назначить список actors
и
сохранить его в нашей базе данных MongoDB как есть, не создавая
отдельной таблицы, содержащей Actor
и ссылаясь на них в наших
документах Movie
movie = Movie.objects.create(
name = "The Matrix",
length = 136,
year = 1999,
actors = ["Keanu Reeves", "Laurence Fishburne"]
)
Запуск этого фрагмента кода приводит к созданию документа MongoDB:
{
"_id" : ObjectId("..."),
"name" : "The Matrix",
"length" : 136,
"year" : 1999,
"actors" : [
"Keanu Reeves",
"Laurence Fishburne"
]
}
Мы также можем ListField
extend()
ListField и добавить к нему
дополнительные значения:
movie.actors.extend(['Carrie-Ann Moss'])
Это приводит к обновленному документу BSON:
{
"_id" : ObjectId("..."),
"name" : "The Matrix",
"length" : 136,
"year" : 1999,
"actors" : [
"Keanu Reeves",
"Laurence Fishburne",
"Carrie-Ann Moss",
"Carrie-Ann Moss"
]
}
SetField
SetField
- это то же самое, что и ListField
за исключением того, что
он интерпретируется как набор Python, что означает, что дублирование не
допускается.
Если мы добавим одного и того же актера дважды:
movie.actors.extend(['Carrie-Ann Moss'])
Мы быстро понимаем, что результат немного странный:
{
"_id" : ObjectId("..."),
"name" : "The Matrix",
"length" : 136,
"year" : 1999,
"actors" : [
"Keanu Reeves",
"Laurence Fishburne",
"Carrie-Ann Moss"
]
}
Поскольку мы хотели бы избежать дублирования записей, чтобы каждый
человек оставался фактическим человеком, имеет смысл сделать actors
SetField
вместо ListField
:
from django.db import models
from djangotoolbox.fields import ListField
class Movie(models.Model):
name = models.CharField()
length = models.IntegerField()
year = models.IntegerField()
actors = SetField()
Теперь мы можем добавить несколько актеров, некоторые из которых являются дубликатами, и у нас будут только уникальные дополнения:
movie = Movie.objects.create(
name = "John Wick",
length = 102,
year = 2014,
actors = ["Keanu Reeves", "Keanu Reeves", "Bridget Moynahan"]
)
Однако в итоговом документе будет только одна запись для
"Keanu Reeves"
, единственная и неповторимая:
{
"_id" : ObjectId("..."),
"name" : "John Wick",
"length" : 102,
"year" : 2014,
"actors" : [
"Keanu Reeves",
"Bridget Moynahan"
]
}
DictField
DictField
хранит словари Python как еще один документ BSON в вашем
собственном документе. Это предпочтительнее, если вы не уверены, как
может выглядеть словарь - и у вас нет для него заранее определенной
структуры.
С другой стороны, если структура знакома, рекомендуется использовать
встроенные модели в качестве моделей внутри моделей. Например, Actor
может быть модель сама по себе, и мы могли бы позволить Movie
модель
имеет несколько встроенных Actor
моделей. С другой стороны, если
необходимо добавить переменный набор значений, они могут быть отображены
как элементы «ключ-значение» и сохранены через DictField
.
Например, добавим reviews
, в котором может быть 0..n
отзывов. Хотя
reviews
имеют предсказуемую структуру ( name
, grade
, comment
), мы реализуем их как DictField
, прежде чем сделать отдельную
Model
для actors
и reviews
:
from django.db import models
from djangotoolbox.fields import SetField
from djangotoolbox.fields import DictField
class Movie(models.Model):
name = models.CharField()
length = models.IntegerField()
year = models.IntegerField()
actors = SetField()
reviews = DictField()
Теперь при создании фильмов мы можем добавлять словари рецензентов и их рецензии на фильмы:
movie = Movie.objects.create(
name = "Good Will Hunting",
length = 126,
year = 1997,
actors = ["Matt Damon", "Stellan Skarsgard"],
reviews = [
{"Portland Oregonian" : "With its sweet soul and sharp mind..."},
{"Newsweek" : "Gus Van Sant, working from the tangy, well-written script..."}
]
)
Выполнение этого кода приводит к:
{
"_id" : ObjectId("..."),
"name" : "Good Will Hunting",
"length" : 126,
"year" : 1997,
"actors" : [
"Matt Damon",
"Stellan Skarsgard"
],
"reviews" : [
{"Portland Oregonian" : "With its sweet soul and sharp mind..."},
{"Newsweek": "Gus Van Sant, working from the tangy, well-written script..."}
]
}
Встроенные модели
Теперь reviews
, возможно, будет иметь такую же структуру - name
за
которым следует comment
. actors
- это больше, чем просто их имена -
у них есть last_name
, date_of_birth
и другие характеристики.
Для обоих из них мы можем создавать автономные модели, как если бы мы
делали это с реляционными базами данных. Однако с реляционными базами
данных мы сохраняли бы их в их собственных таблицах и связывали бы с
ними из таблицы Movie
С помощью MongoDB мы можем превратить их во встроенные модели - целые документы, встроенные в другой документ.
Давайте еще раз изменим наш Movie
:
from django.db import models
from djangotoolbox.fields import ListField, EmbeddedModelField
class Movie(models.Model):
name = models.CharField(max_length=100)
length = models.IntegerField()
year = models.IntegerField()
actors = SetField(EmbeddedModelField("Actor"))
reviews = SetField(EmbeddedModelField("Review"))
Здесь мы создали SetField
(который также мог быть чем-то вроде
ListField
) как для actors
и для reviews
. Однако на этот раз мы
сделали их SetField
из других моделей , передав EmbeddedModelField
в конструкторы SetField
.
Мы также указали, какие модели в конструкторе класса
EmbeddedModelField
Теперь давайте определим и эти два в файле models.py
class Actor(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
date_of_birth = models.CharField(max_length=11)
class Review(models.Model):
name = models.CharField(max_length=30)
comment = models.CharField(max_length=300)
Теперь, при создании Movie
и сохранении его в базе данных, мы также
можем добавить к нему новые экземпляры Actor
и Review
movie = Movie.objects.create(
name = "Focus",
length = 105,
year = 2015,
actors = [
Actor(
first_name="Will",
last_name="Smith",
date_of_birth="25.09.1968."
)
],
reviews = [
Review(
name = "Portland Oregonian",
comment = "With its sweet soul and sharp mind..."
),
Review(
name = "Newsweek",
comment = "Gus Van Sant, working from the tangy, well-written script..."
)
]
)
Это создает новые документы BSON для каждого Actor
и Review
в
наборах и сохраняет их как встроенные объекты в наш документ movie
{
"_id" : ObjectId("..."),
"name" : "Focus",
"length" : 105,
"year" : 2015,
"actors" : [
{
"name" : "Will",
"last_name" : "Smith",
"date_of_birth" : "25.09.1968"
}
],
"reviews" : [
{
"name" : "Portland Oregonian",
"comment" : "With its sweet soul and sharp mind..."
},
{
"name" : "Newsweek",
"comment" : "Gus Van Sant, working from the tangy, well-written script..."
}
]
}
Каждая запись в массиве BSON reviews
является отдельным экземпляром
Review
То же самое и с actors
.
Обработка файлов
MongoDB имеет встроенную спецификацию для хранения / извлечения файлов в файловой системе под названием GridFS , которая также используется в Django MongoDB Engine.
Примечание. MongoDB хранит файлы, разделяя их на части размером
255 kB
каждая. При доступе к файлу GridFS собирает части и объединяет
их.
Чтобы импортировать систему django_mongodb_engine_storage
модулю
django_mongodb_engine_storage:
from django_mongodb_engine.storage import GridFSStorage
gridfs = GridFSStorage()
uploads_location = GridFSStorage(location = '/uploaded_files')
Еще одно поле, которое мы можем использовать, - это GridFSField()
,
которое позволяет нам указывать поля, которые используют систему GridFS
для хранения данных:
class Movie(models.Model):
name = models.CharField()
length = models.IntegerField()
year = models.IntegerField()
actors = SetField(EmbeddedModelField("Actor"))
reviews = SetField(EmbeddedModelField("Review"))
poster = GridFSField()
Теперь это изображение будет сохраняться кусками и загружаться лениво только по запросу.
Заключение
Подводя итог, можно сказать, что Django MongoDB Engine - довольно мощный движок, и основным недостатком его использования является то, что он работает со старыми версиями Django (1.5) и Python (2.7), тогда как Django теперь имеет 3,2 LTS и поддерживает 1,5. закончился давным-давно. Python находится на уровне 3.9, а поддержка 2.7 закончилась в прошлом году. Вдобавок ко всему, Django MongoDB Engine, похоже, прекратил дальнейшую разработку еще в 2015 году.