--- title: 'Django учебник Часть 3: Использование моделей' slug: Learn/Server-side/Django/Models tags: - Django - данные - модель - туториал translation_of: Learn/Server-side/Django/Models ---
В этой статье показано, как определить модели для LocalLibrary сайта. Она объясняет, что такое модель, как она объявляется, и некоторые из основных типов полей. В ней также кратко показаны некоторые из основных способов доступа к данным модели.
Предпосылки | Django Tutorial Part 2: Creating a skeleton website. |
---|---|
Задача: | Научиться проектировать и создавать свои собственные модели, выбирая подходящие поля. |
Веб-приложения Django получают доступ и управляют данными через объекты Python, называемые моделями. Модели определяют структуру хранимых данных, включая типы полей и, возможно, их максимальный размер, значения по умолчанию, параметры списка выбора, текст справки для документации, текст меток для форм и т. д. Определение модели не зависит от основной базы данных - вы можете выбрать один из нескольких компонентов вашей настройки проекта. После того, как вы выбрали какую базу данных хотите использовать, вам не нужно напрямую работать с ней - вы просто пишете свою структуру модели и код, а Django делает всю грязную работу, связанную с базой данных за вас.
В этом учебнике показано, как определить и получить доступ к моделям на примере LocalLibrary website.
Перед тем, как вы начнёте программировать модели, стоит потратить несколько минут, чтобы подумать о том, какие данные нам нужно хранить, и о взаимоотношениях между разными объектами.
Мы знаем, что нам нужно хранить информацию о книгах (название, резюме, автор, язык, на котором написана книга, категория, ISBN) и что у нас может быть несколько доступных экземпляров (с уникальным глобальным идентификатором, статусом доступности и т. Д.). Нам может потребоваться хранить больше информации об авторе, чем просто их имя, и могут быть несколько авторов с одинаковыми или похожими именами. Мы хотим иметь возможность сортировать информацию на основе названия книги, автора, письменного языка и категории.
При проектировании ваших моделей имеет смысл иметь отдельные модели для каждого «объекта» (группа связанной информации). В этом случае очевидными объектами являются книги, экземпляры книг и авторы.
Вы также можете использовать модели для представления параметров списка выбора (например, как выпадающий список вариантов), вместо жёсткого кодирования выбора на самом веб-сайте - это рекомендуется, когда все варианты неизвестны заранее или могут измениться. Очевидные кандидаты на модели в этом случае включают жанр книги (например, «Научная фантастика», «Французская поэзия» и т. д.) И язык (английский, французский, японский).
Как только мы определились с нашими моделями и полями, нам нужно подумать об отношениях. Django позволяет вам определять отношения, как один к одному (OneToOneField
), один ко многим (ForeignKey
) и многие ко многим (ManyToManyField
).
Диаграмма ассоциации UML, приведённая ниже показывает модели, которые мы определили в этом случае (в виде блоков). Как и выше, мы создали модели для книги (общие сведения о книге), экземпляр книги (статус конкретных физических копий книги, доступных в системе) и автора.Мы также решили создать модель для жанра, чтобы можно было создавать / выбирать значения через интерфейс администратора. Мы решили не иметь модель для BookInstance: status - мы жёстко закодировали значения (LOAN_STATUS), потому что мы не ожидаем их изменения. В каждом из полей вы можете увидеть имя модели, имена и типы полей, а также методы и их типы возврата.
На диаграмме также показаны зависимости между моделями, включая их множители. Множители представляют собой числа на диаграмме, показывающие минимум и максимум единиц каждой модели, которые могут присутствовать в этой связи. Например, соединительная линия между ящиками показывает, что книга и жанр связаны между собой. Цифры, близкие к модели жанра, показывают, что у книги может быть один или несколько жанров (сколько угодно), а числа на другом конце строки рядом с моделью книги показывают, что у жанра может быть ноль или более связанных книг.
Примечание. В следующем разделе приведён базовый пример, поясняющий, как модели определяются и используются. Когда вы его прочитаете, подумайте, как мы построим каждую из моделей на диаграмме выше.
В этом разделе представлен краткий обзор того, как определяется модель, и некоторые из наиболее важных полей и аргументы поля.
Модели обычно определяются в приложении models.py. Они реализуются как подклассы django.db.models.Model
, и могут включать поля, методы и метаданные. В приведённом ниже фрагменте кода показана «типичная» модель, названная MyModelName
:
from django.db import models class MyModelName(models.Model): """ A typical class defining a model, derived from the Model class. """ # Fields my_field_name = models.CharField(max_length=20, help_text="Enter field documentation") ... # Metadata class Meta: ordering = ["-my_field_name"] # Methods def get_absolute_url(self): """ Returns the url to access a particular instance of MyModelName. """ return reverse('model-detail-view', args=[str(self.id)]) def __str__(self): """ String for representing the MyModelName object (in Admin site etc.) """ return self.field_name
В следующих разделах мы подробно рассмотрим каждый элемент внутри модели:
Модель может иметь произвольное количество полей любого типа - каждый представляет столбец данных, который мы хотим сохранить в одной из наших таблиц базы данных. Каждая запись (строка) базы данных будет состоять из одного значения каждого поля. Давайте рассмотрим приведённый выше пример:
my_field_name = models.CharField(max_length=20, help_text="Enter field documentation")
Наш вышеприведённый пример имеет одно поле, называемое my_field_name
, типа models.CharField
— что означает, что это поле будет содержать строки буквенно-цифровых символов. Типы полей назначаются с использованием определённых классов, которые определяют тип записи, которая используется для хранения данных в базе данных, а также критерии проверки, которые должны использоваться, когда значения получены из формы HTML (то есть, что составляет действительное значение). Типы полей также могут принимать аргументы, которые дополнительно определяют, как поле хранится или может использоваться. В этом случае мы даём нашему полю два аргумента:
max_length=20
— Указывает, что максимальная длина значения в этом поле составляет 20 символов.help_text="Enter field documentation"
— предоставляет текстовую метку для отображения, чтобы помочь пользователям узнать, какое значение необходимо предоставить, когда это значение должно быть введено пользователем через HTML-форму.Имя поля используется для обращения к нему в запросах и шаблонах. В полях также есть метка, которая задаётся как аргумент (verbose_name), либо выводится путём заглавной буквы первой буквы имени переменной поля и замены любых символов подчёркивания пробелом (например, my_field_name будет иметь метку по умолчанию My field name).
Порядок, в котором объявляются поля, будет влиять на их порядок по умолчанию, если модель отображается в форме (например, на сайте администратора), хотя это может быть переопределено.
Следующие общие аргументы могут использоваться при объявлении многих / разных типов полей:
Есть много других вариантов - вы можете просмотреть full list of field options here.
Следующие общие аргументы могут использоваться при объявлении многих / разных типов полей:
max_length
для поля, но это используется только тогда, когда поле отображается в формах (оно не применяется на уровне базы данных).auto_now=True
(для установки поля на текущую дату каждый раз, когда модель сохраняется), auto_now_add (только для установки даты, когда модель была впервые создана) и по умолчанию (чтобы установить дату по умолчанию, которую пользователь может переустановить).ImageField
просто добавляет дополнительную проверку, что загруженный файл является изображением). Они имеют параметры для определения того, как и где хранятся загруженные файлы.models.SET_NULL
просто установило бы значение NULL)Существует много других типов полей, включая поля для разных типов чисел (большие целые числа, малые целые числа, дробные), логические значения, URL-адреса, slugs, уникальные идентификаторы и другие «связанные с временем» сведения (продолжительность, время и т. д.). Вы можете просмотреть full list here.
Вы можете объявить метаданные на уровне модели для своей модели, объявив класс Meta, как показано на рисунке.
class Meta: ordering = ["-my_field_name"] ...
Одной из наиболее полезных функций этих метаданных является управление сортировка записей, возвращаемых при запросе типа модели. Вы можете сделать это, указав соответствия названия полей для сортировки, как показано выше. Порядок будет зависеть от типа поля (поля символов отсортированы в алфавитном порядке, а поля даты отсортированы в хронологическом порядке). Как показано выше, вы можете префикс имени поля минус-символом (-), чтобы изменить порядок сортировки.
Например, если мы решили сортировать книги по умолчанию:
ordering = ["title", "-pubdate"]
Книги будут отсортированы по алфавиту по названию, от A-Z, а затем по дате публикации внутри каждого названия, от самого нового до самого старого.
Другим распространённым атрибутом является verbose_name, подробное имя для класса в единственной и множественной форме:
verbose_name = "BetterName"
Другие полезные атрибуты позволяют создавать и применять новые «разрешения доступа» для модели (разрешения по умолчанию применяются автоматически), разрешить упорядочение на основе другого поля или объявить, что класс является «абстрактным» (базовый класс, для которого вы не можете создавать записи, и вместо этого будет создан для создания других моделей). Многие другие параметры метаданных управляют тем, какая база данных должна использоваться для модели и как хранятся данные (это действительно полезно, если вам нужно сопоставить модель с существующей базой данных). Полный список опций метаданных доступен здесь: Model metadata options (Django документация).
Модель также может иметь методы. Минимально в каждой модели вы должны определить стандартный метод класса для Python __str __ (), чтобы вернуть удобочитаемую строку для каждого объекта. Эта строка используется для представления отдельных записей на сайте администрирования (и в любом другом месте, где вам нужно обратиться к экземпляру модели). Часто это возвращает поле названия или имени из модели.
def __str__(self): return self.field_name
Другим распространённым методом включения в модели Django является get_absolute_url (), который возвращает URL-адрес для отображения отдельных записей модели на веб-сайте (если вы определяете этот метод, тогда Django автоматически добавит кнопку «Просмотр на сайте» на экранах редактирования записей модели на сайте администратора). Типичный шаблон для get_absolute_url () показан ниже.
def get_absolute_url(self): """ Returns the url to access a particular instance of the model. """ return reverse('model-detail-view', args=[str(self.id)])
Примечание. Предполагается, что вы будете использовать URL-адреса, например / myapplication / mymodelname / 2, для отображения отдельных записей для вашей модели (где «2» - это идентификатор для определённой записи), вам нужно будет создать URL-карту, чтобы передать ответ и идентификатор «Образцовое представление модели» (которое будет выполнять работу, необходимую для отображения записи). Вышеуказанная функция reverse () может «перевернуть» ваш URL-адрес (в приведённом выше примере с именем «model-detail-view»), чтобы создать URL-адрес правильного формата.
Конечно, для выполнения этой работы вам всё равно придётся писать сопоставление URL-адрес, просмотр и шаблон!
Вы также можете определить любые другие методы, которые вам нравятся, и вызывать их из вашего кода или шаблонов (при условии, что они не принимают никаких параметров).
После того, как вы определили свои классы моделей, вы можете использовать их для создания, обновления или удаления записей и для запуска запросов для получения всех записей или отдельных подмножеств записей. Мы покажем вам, как это сделать в учебнике, когда мы определяем наши представления, с кратким обзором.
Чтобы создать запись, вы можете определить экземпляр модели, а затем вызвать метод save ().
# Create a new record using the model's constructor. a_record = MyModelName(my_field_name="Instance #1") # Save the object into the database. a_record.save()
Примечание. Если вы не указали какое-либо поле в качестве primary_key, новая запись будет выдаваться автоматически, с идентификатором имени поля. Вы можете запросить это поле после сохранения указанной выше записи, и оно будет иметь значение 1.
Вы можете получить доступ к полям в этой новой записи с использованием синтаксиса точек и изменить значения. Вы должны вызвать save (), чтобы сохранить изменённые значения в базе данных.
# Access model field values using Python attributes. print(a_record.id) #should return 1 for the first record. print(a_record.my_field_name) # should print 'Instance #1' # Change record by modifying the fields, then calling save(). a_record.my_field_name="New Instance Name" a_record.save()
Вы можете искать записи, соответствующие определённым критериям, используя атрибут объектов модели (предоставляемый базовым классом).
Примечание. Объяснение того, как искать записи, используя «абстрактную» модель и имена полей, может быть немного запутанным. В приведённом ниже обсуждении мы будем ссылаться на модель книги с полями названия и жанра, где жанр также является моделью с единственным именем в поле.
Мы можем получить все записи для модели как объект QuerySet, используя objects.all()
. QuerySet - это итерируемый объект, означающий, что он содержит несколько объектов, которые мы можем перебирать / прокручивать.
all_books = Book.objects.all()
Метод filter()
Django позволяет отфильтровать возвращаемый QuerySet
для соответствия указанному текстовому или числовому полю по конкретным критериям. Например, чтобы отфильтровать книги, содержащие слово «wild» («дикие») в заголовке, а затем подсчитать их, мы могли бы сделать следующее.
wild_books = Book.objects.filter(title__contains='wild') number_wild_books = Book.objects.filter(title__contains='wild').count()
Соответствующие поля и тип соответствия определяются в имени параметра фильтра, используя формат: field_name__match_type
(обратите внимание на двойное подчёркивание между заголовком выше). Выше мы фильтруем заголовок с учётом регистра. Есть много других типов совпадений, которые вы можете сделать: icontains
(без учёта регистра), iexact
(точное совпадение без учёта регистра), exact
(точное совпадение с учётом регистра ) и in
, gt
(больше), startswith
и т. д смотреть полный список (Django Docs, [EN]).
В некоторых случаях вам нужно будет фильтровать поле, которое определяет отношение «один ко многим» к другой модели (например, ForeignKey
). В этом случае вы можете «индексировать» поля в связанной модели с дополнительными двойными подчёркиваниями. Так, например, чтобы фильтровать книги с определённым жанровым рисунком, вам нужно будет указывать имя в поле жанра, как показано ниже:
books_containing_genre = Book.objects.filter(genre__name__icontains='fiction') # Will match on: Fiction, Science fiction, non-fiction etc.
Примечание: Вы можете использовать символы подчёркивания (__) для навигации по многим уровням отношений (ForeignKey / ManyToManyField) по своему усмотрению. Например, книга, имеющая разные типы, определяемая с использованием дополнительной связи «обложка», может иметь имя параметра: type__cover__name__exact = 'hard'.
Существует гораздо больше возможностей для запросов, включая обратные поиски от связанных моделей, цепочки фильтров, возврат меньшего набора значений и т. д. Для получения дополнительной информации см. Making queries (Django Docs, [EN]).
В этом разделе мы начнём определять модели для библиотеки. Откройте models.py (в / locallibrary / catalog /). Шаблон в верхней части страницы импортирует модуль моделей, который содержит базовый класс модели models.Model
, от которого наследуются наши модели.
from django.db import models # Create your models here.
Скопируйте приведённый ниже код модели Genre
и вставьте его в нижнюю часть вашего файла models.py
. Эта модель используется для хранения информации о категории книг - например, будь то художественная или документальная, роман или военно-историческая и т. д. Как уже упоминалось выше, мы создали жанр как модель, а не как свободный текст или список выбора, чтобы возможные значения могли управляться через базу данных, а не были закодированными.
class Genre(models.Model): """ Model representing a book genre (e.g. Science Fiction, Non Fiction). """ name = models.CharField(max_length=200, help_text="Enter a book genre (e.g. Science Fiction, French Poetry etc.)") def __str__(self): """ String for representing the Model object (in Admin site etc.) """ return self.name
Модель имеет один CharField
field (имя), которое используется для описания жанра (оно ограничено 200 символами и имеет некоторый help_text
. В конце модели мы объявляем метод __str__()
, который просто возвращает имя жанра, определённого конкретной записью. Verbose name не был определён, поэтому поле будет называться Name
в формах.
Скопируйте модель книги ниже и снова вставьте её в нижнюю часть файла. Модель книги представляет всю информацию о доступной книге в общем смысле, но не конкретный физический «экземпляр» или «копию» для временного использования. Модель использует CharField для представления названия книги и isbn (обратите внимание, как isbn указывает свой ярлык как «ISBN», используя первый неименованный параметр, поскольку в противном случае ярлык по умолчанию был бы «Isbn»). Модель использует TextField для summary, потому что этот текст, возможно, должен быть очень длинным.
from django.urls import reverse #Used to generate URLs by reversing the URL patterns class Book(models.Model): """ Model representing a book (but not a specific copy of a book). """ title = models.CharField(max_length=200) author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True) # Foreign Key used because book can only have one author, but authors can have multiple books # Author as a string rather than object because it hasn't been declared yet in the file. summary = models.TextField(max_length=1000, help_text="Enter a brief description of the book") isbn = models.CharField('ISBN',max_length=13, help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>') genre = models.ManyToManyField(Genre, help_text="Select a genre for this book") # ManyToManyField used because genre can contain many books. Books can cover many genres. # Genre class has already been defined so we can specify the object above. def __str__(self): """ String for representing the Model object. """ return self.title def get_absolute_url(self): """ Returns the url to access a particular book instance. """ return reverse('book-detail', args=[str(self.id)])
Жанр представляет из себя ManyToManyField, так что книга может иметь несколько жанров, а жанр может иметь много книг. Автор объявляется через ForeignKey, поэтому в каждой книге будет только один автор, но у автора может быть много книг (на практике книга может иметь несколько авторов, но не в такой реализации!)
В обоих типах полей соответствующий класс модели объявляется как первый неименованный параметр, используя либо класс модели, либо строку, содержащую имя соответствующей модели. Вы должны использовать имя модели как строку, если связанный класс ещё не был определён в этом файле до того, как он будет указан! Другими параметрами, представляющими интерес для поля автора, являются null=True
, которое позволяет базе данных хранить значение Null
, если автор не выбран, и on_delete = models. SET_NULL
установит значение автора в Null, если связанная с автором запись будет удалена.
Модель также определяет __str __ (), используя поле заголовка книги для представления книги. Окончательный метод get_absolute_url () возвращает URL-адрес, который можно использовать для доступа к подробной записи для этой модели (для этого нам нужно будет определить сопоставление URL-адресов, в котором содержится подробная информация о книге, и определить связанное представление и шаблон ).
Затем скопируйте модель BookInstance (показано ниже) под другие модели. BookInstance представляет собой определённую копию книги, которую кто-то может брать взаймы, и включает информацию о том, доступна ли копия или в какой день она ожидается, «отпечаток» или сведения о версии, а также уникальный идентификатор книги в библиотеке. Теперь некоторые из полей и методов будут знакомы. Модель использует
import uuid # Required for unique book instances class BookInstance(models.Model): """ Model representing a specific copy of a book (i.e. that can be borrowed from the library). """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text="Unique ID for this particular book across whole library") book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True) imprint = models.CharField(max_length=200) due_back = models.DateField(null=True, blank=True) LOAN_STATUS = ( ('m', 'Maintenance'), ('o', 'On loan'), ('a', 'Available'), ('r', 'Reserved'), ) status = models.CharField(max_length=1, choices=LOAN_STATUS, blank=True, default='m', help_text='Book availability') class Meta: ordering = ["due_back"] def __str__(self): """ String for representing the Model object """ return '%s (%s)' % (self.id,self.book.title)
Мы дополнительно объявляем несколько новых типов полей:
UUIDField
используется для поля id, чтобы установить его как primary_key для этой модели. Этот тип поля выделяет глобальное уникальное значение для каждого экземпляра (по одному для каждой книги, которую вы можете найти в библиотеке).DateField
используется для данных due_back (при которых ожидается, что книга появится после заимствования или обслуживания). Это значение может быть blank или null (необходимо, когда книга доступна). Метаданные модели (Class Meta) используют это поле для упорядочивания записей, когда они возвращаются в запросе.Модель __str __ () представляет объект BookInstance, используя комбинацию его уникального идентификатора и связанного с ним заголовка книги.
Примечание. Немного Python:
Скопируйте модель автора (показано ниже) под существующим кодом в models.py.
Теперь все поля/методы должны быть знакомы. Модель определяет автора как имя, фамилию, дату рождения и (необязательную) дату смерти. Он указывает, что по умолчанию __str __ () возвращает имя в фамилии, порядковый номер первого имени. Метод get_absolute_url () отменяет сопоставление URL-адреса автора с целью получения URL-адреса для отображения отдельного автора.
class Author(models.Model): """ Model representing an author. """ first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) date_of_birth = models.DateField(null=True, blank=True) date_of_death = models.DateField('Died', null=True, blank=True) def get_absolute_url(self): """ Returns the url to access a particular author instance. """ return reverse('author-detail', args=[str(self.id)]) def __str__(self): """ String for representing the Model object. """ return '%s, %s' % (self.last_name, self.first_name)
Теперь все ваши модели созданы. Теперь переустановите миграцию базы данных, чтобы добавить их в свою базу данных.
python3 manage.py makemigrations
python3 manage.py migrate
Представьте себе, что местный благотворитель жертвует ряд новых книг, написанных на другом языке (скажем, фарси). Задача состоит в том, чтобы определить, как они будут лучше всего представлены на нашем веб-сайте библиотеки, а затем добавить их в модели.
Некоторые вещи, которые следует учитывать:
После того, как вы решили, добавьте поле. Вы можете увидеть наше решение на Github here.
В этой статье мы узнали, как определять модели, а затем использовать эту информацию в разработке и внедрении соответствующих моделей для сайта LocalLibrary.
На этом этапе мы отвлечёмся от создания сайта и проверим Django Administration site. Этот сайт позволит нам добавить некоторые данные в библиотеку, которые мы можем отобразить с помощью наших (ещё не созданных) представлений и шаблонов.
{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}