Pull to refresh

Перевод Django Documentation: Models. Part 2

Reading time 10 min
Views 17K
image

Доброго времени суток!

Этот топик является продолжением перевода документации Django, если быть точным — раздела о моделях.

Перевод Django Documentation: Models. Part 1

_____Отношения между моделями
_______Отношение многие-к-одному
_______Отношение многие-к-многим
_______Дополнительные поля в отношении многие-к-многим
_______Отношение один-к-одному
_____Модели и файлы
_____Ограничения на имена полей
_____Собственные типы полей


Перевод Django Documentation: Models. Part 3
Перевод Django Documentation: Models. Part 4 (Last)



Отношения между моделями


Очевидно, что главное преимущество реляционных баз данных заключается в способности задавать отношения между таблицами. Django предоставляет возможности для определения трех наиболее распространенных типов отношений: многие-к-одному, многие-к-многим и один-к-одному.



Отношение многие-к-одному

Для определения данного вида отношений используется ForeignKey. Его использование ничем не отличается от использования других типов полей: просто добавьте соответствующий атрибут в вашу модель.

При создании поля с использованием ForeignKey, одноименному методу следует передать один позиционный аргумент: класс, на который будет ссылаться ваша модель.

Например, если машина (Car) имеет производителя (Manufacturer) (производитель создает большое количество машин, однако каждая машина имеет лишь одного производителя), используется следующее определение:
Copy Source | Copy HTML<br/>class Manufacturer(models.Model):<br/>    # ...<br/> <br/>class Car(models.Model):<br/>    manufacturer = models.ForeignKey(Manufacturer)<br/>    # ... <br/>

Так же вы можете создать рекурсивные отношения (объект с отношением многие-к-одному, ссылающийся на самого себя) и отношения с еще не определенной моделью; более подробно здесь.

В качестве имени поля типа ForeignKey (manufacturer в примере, приведенном выше) мы советуем использовать имя модели, на которую ссылается ваш класс, в нижнем регистре. Это необязательное требование, и вы можете называть поле так, как хотите. Например:
Copy Source | Copy HTML<br/>class Car(models.Model):<br/>    company_that_makes_it = models.ForeignKey(Manufacturer)<br/>    # ... <br/>


image
Более подробный пример вы можете найти здесь — отношение многие-к-одному: пример

Поля типа ForeignKey так же могут иметь ряд дополнительных аргументов, которые рассмотрены в описании полей моделей. Эти необязательные параметры позволяют более точно определить работу отношений.



Отношение многие к многим

Для определения данного вида отношений используется ManyToManyField. Его использование ничем не отличается от использования других типов полей: просто добавьте соответствующий атрибут в вашу модель.

При создании поля с использованием ManyToManyField, одноименному методу следует передать один позиционный аргумент: класс, на который будет ссылаться ваша модель.

Например, если пицца (Pizza) имеет начинку (Topping) (одна пицца может иметь множество начинок, которые в свою очередь могут содержаться во многих пиццах), вы можете представить это так:
Copy Source | Copy HTML<br/>class Topping(models.Model):<br/>    # ...<br/> <br/>class Pizza(models.Model):<br/>    # ...<br/>    toppings = models.ManyToManyField(Topping) <br/>

Так же, как и в случае с ForeignKey, вы можете создать рекурсивные отношения (объект с отношением многие-к-одному, ссылающийся на самого себя) и отношения с еще не определенной моделью; более подробно здесь.

В качестве имени поля типа ManyToManyField (toppings в примере, приведенном выше) мы советуем использовать существительное во множественном числе, которое описывает множество связанных отношением объектов.

Не важно, какая из моделей имеет атрибут типа ManyToManyField, главное чтобы он задавался лишь в одной из них.

Как правило, поле типа ManyToManyField определяется в объекте, который впоследствии будет изменяться в интерфейсе администратора, если вы используете встроенную админку Django (прим.пер. извините, или сленг или тавтология). В примере выше начинки (toppings) находятся на пицце (Pizza), потому что более привычно для нас представлять себе пиццу, имеющую разные начинки, нежели чем начинку, содержащуюся на множестве пицц. Если описать модель так, как показано выше, форма Pizza позволит пользователям выбирать начинки.

image
Более подробный пример вы можете найти здесь — отношение многие-к-многим: пример

Поля типа ManyToManyField так же могут иметь ряд дополнительных аргументов, которые рассмотрены в описании полей моделей. Эти необязательные параметры позволяют более точно определить работу отношений.



Дополнительные поля в отношении многие-к-многим
добавлено в версии Django 1.0: пожалуйста, прочтите примечания к релизу.

Пока вы имеете дело с тривиальными отношениями вида многие-к-многим, такими как объединение и установление соответствия между пиццами и начинками, все, что вам нужно это стандартный тип ManyToManyField. Однако иногда вам может понадобиться ассоциирование данных с помощью отношения между двумя моделями.

Например, рассмотрим случай когда приложение отслеживает группы, в которых некоторые музыканты принимали участие. Отношение между музыкантом и группами, участником которых он являлся или является, будут вида многие-к-многим, поэтому для его представления вы можете использовать ManyToManyField. Однако так же вас может интересовать большое количество деталей, таких как дата вступления в группу или причина, по которой музыкант ее покинул.

Для таких ситуаций Django предоставляет вам возможность определить отдельную (промежуточную) модель, которая будет использоваться для управление отношениями многие-к-многим. Вы можете создать дополнительные поля в промежуточной модели. Промежуточная модель взаимодействует с ManyToManyField с помощью аргумента through, который выступает в качестве посредника. Для нашего музыкального (:)) примера код будет выглядеть примерно так:
Copy Source | Copy HTML<br/>class Person(models.Model):<br/>    name = models.CharField(max_length=128)<br/> <br/>    def __unicode__(self):<br/>        return self.name<br/> <br/>class Group(models.Model):<br/>    name = models.CharField(max_length=128)<br/>    members = models.ManyToManyField(Person, through='Membership')<br/> <br/>    def __unicode__(self):<br/>        return self.name<br/> <br/>class Membership(models.Model):<br/>    person = models.ForeignKey(Person)<br/>    group = models.ForeignKey(Group)<br/>    date_joined = models.DateField()<br/>    invite_reason = models.CharField(max_length=64) <br/>

При создании промежуточной модели вы явно указываете внешние ключи для моделей, которые вовлечены в отношение вида многие-к-многим. Это однозначное объявление и определяет способы взаимодействия объектов.

Существует несколько ограничений, касающихся промежуточных моделей:
  • Ваша промежуточная модель должна содержать один и только один внешний ключ к целевой модели (в нашем примере это Person), иначе будет сгенерирована ошибка проверки (validation error).
  • Ваша промежуточная модель должна содержать один и только один внешний ключ к исходной модели (в нашем примере это Group), иначе будет сгенерирована ошибка проверки (validation error).
  • Единственным исключением является модель, которая имеет отношение многие-к-многим сама с собой и ссылается на себя с помощью промежуточной модели. В этом случае разрешается использовать два внешних ключа к одной и той же модели, но они буду рассматриваться как две различные части в отношениях вида многие-к-многим.
  • Для определения модели, которая ссылается сама на себя с помощью промежуточной модели, вы должны использовать symmetrical=False (подробнее в справке по полям моделей).

    Теперь, после того как вы настроили ManyToManyField для взаимодействия с вашей промежуточной моделью, вы можете начать создание нескольких отношений вида многие-к-многим. Делается это путем создания экземпляров вашей промежуточной модели:
    Copy Source | Copy HTML<br/>>>> ringo = Person.objects.create(name="Ringo Starr")<br/>>>> paul = Person.objects.create(name="Paul McCartney")<br/>>>> beatles = Group.objects.create(name="The Beatles")<br/>>>> m1 = Membership(person=ringo, group=beatles,<br/>... date_joined=date(1962, 8, 16),<br/>... invite_reason= "Needed a new drummer.")<br/>>>> m1.save()<br/>>>> beatles.members.all()<br/>[<Person: Ringo Starr>]<br/>>>> ringo.group_set.all()<br/>[<Group: The Beatles>]<br/>>>> m2 = Membership.objects.create(person=paul, group=beatles,<br/>... date_joined=date(1960, 8, 1),<br/>... invite_reason= "Wanted to form a band.")<br/>>>> beatles.members.all()<br/>[<Person: Ringo Starr>, <Person: Paul McCartney>] <br/>

    Не очень похоже на обычные поля: вы не можете использовать методы add и create, а также операцию присваивания (например, beatles.members = [...]) для определения отношений:
    Copy Source | Copy HTML<br/># THIS WILL NOT WORK<br/>>>> beatles.members.add(john)<br/># NEITHER WILL THIS<br/>>>> beatles.members.create(name="George Harrison")<br/># AND NEITHER WILL THIS<br/>>>> beatles.members = [john, paul, ringo, george] <br/>

    Почему? Вы не можете просто создать отношение между Person и Group, поэтому вы должны указать все детали отношения, требуемые промежуточной моделью Membership. Простые методы add, create и присваивание не предоставляют возможности определить дополнительные детали. Поэтому они отключены в отношения вида многие-к-многим с использованием промежуточной модели. Единственный вариант создания данного вида отношений, заключается в создании экземпляров промежуточной модели.

    Метод remove отключен по этим же причинам. Однако вы можете использовать метод clear() для удаления всех отношений вида многие-к-многим отношений экземпляра:
    Copy Source | Copy HTML<br/># Beatles have broken up<br/>>>> beatles.members.clear() <br/>

    Итак, вы создали отношения вида многие-к-многим путем создания экземпляров промежуточной модели, теперь вы можете оформлять запросы. Так же как и и в случае с нормальным вариантом отношений, вы можете составлять запросы, используя атрибуты модели:
    Copy Source | Copy HTML<br/># Find all the groups with a member whose name starts with 'Paul'<br/>>>> Group.objects.filter(members__name__startswith='Paul')<br/>[<Group: The Beatles>] <br/>

    Так как вы используете промежуточную модель, вы также можете оформлять запросы, используя атрибуты модели-посредника:
    Copy Source | Copy HTML<br/># Find all the members of the Beatles that joined after 1 Jan 1961<br/>>>> Person.objects.filter(<br/>... group__name='The Beatles',<br/>... membership__date_joined__gt=date(1961,1,1))<br/>[<Person: Ringo Starr] <br/>




    Отношение один-к-одному

    Для определения данного вида отношений используется OneToOneField. Его использование ничем не отличается от использования других типов полей: просто добавьте соответствующий атрибут в вашу модель.

    Этот вид отношений наиболее полезен в случае, когда один из объектов, связанных отношением, как-то расширяет или дополняет другой.

    При создании поля с использованием OneToOneField, одноименному методу следует передать один позиционный аргумент: класс, на который будет ссылаться ваша модель.

    Например, если вы решили создать базу данных «Places», вы, скорее всего, добавите в нее совершенно стандартные вещи, такие как адрес, телефон и так далее. Если же вы захотите создать новую базу данных о ресторанах, которые располагаются в местах из первой базы данных, вместо повторения и дублирования информации в полях модели Restaurant, вы можете установить отношение один-к-одному между Restaurant и Place с помощью OneToOneField (потому что рестаран, фактически, является местом; чтобы справится с этой задачей вам придется использовать наследование, которое неявно включает в себя вид отношений один-к-одному).

    Так же, как и в случае с ForeignKey, вы можете создать рекурсивные отношения и отношения с еще не определенной моделью; более подробно здесь.

    image
    Более подробный пример вы можете найти здесь — отношение один-к-одному: пример

    добавлено в версии Django 1.0: пожалуйста, прочтите примечания к релизу.
    Поля типа OneToOneField принимают один необязательный аргумент, рассмотренный в описании полей моделей.

    Ранее классы OneToOneField автоматически становились первичными ключами модели. Это больше не так (хотя возможность установки primary_key вручную осталась). Таким образом, теперь возможно иметь несколько полей типа OneToOneField в одной модели.



    Модели и файлы


    Вполне возможно связать две модели из разных приложений. Для это следует импортировать нужную модель в верхнюю часть нашей модели, а потом просто сослаться на другой класс, если это будет нужно. Например:
    Copy Source | Copy HTML<br/>from mysite.geography.models import ZipCode<br/> <br/>class Restaurant(models.Model):<br/>    # ...<br/>    zip_code = models.ForeignKey(ZipCode) <br/>




    Ограничения на имена полей


    Django устанавливает два ограничения на имена полей:
    1. Имя поля не может быть зарезервированным словом языка Python, иначе это вызовет синтаксическую ошибку. Например:
      Copy Source | Copy HTML<br/>class Example(models.Model):<br/>    pass = models.IntegerField() # 'pass' is a reserved word! <br/>
    2. Имя поля не может содержать более одного символа подчеркивания подряд. Это является следствием системы поиска запросов в Django. Например:
      Copy Source | Copy HTML<br/>class Example(models.Model):<br/>    foo__bar = models.IntegerField() # 'foo__bar' has two underscores! <br/>


    Эти ограничения можно обойти, потому что ваши поля не обязательно должны соответствовать названию колонки в базе данных (см. db_column option).

    Зарезервированные слова SQL, такие как join, where или select могут быть использованы в качестве имен полей, в связи с тем, что Django «покидает» все столбцы и колонки базы данных при каждом SQL-запросе. В механизмах базы данных используется ссылочный синтаксис.



    Собственные типы полей

    добавлено в версии Django 1.0: пожалуйста, прочтите примечания к релизу.

    Если ни один из существующих типов полей не может быть использован для достижения ваших целей, или если вы хотите воспользоваться преимуществами одного из мало распространенных типов колонок, вы можете создать свой собственный класс поля. Полная информация о создании полей предоставлена в разделе написание собственных типов полей.



    На сегодня все :) to be continued
    С радостью выслушаю любые ваши предложения, вопросы и замечания.

    Перевод Django Documentation: Models. Part 1
    Перевод Django Documentation: Models. Part 3
    Перевод Django Documentation: Models. Part 4 (Last)
Tags:
Hubs:
+45
Comments 58
Comments Comments 58

Articles