Для чего используется `related_name` в Django?
Какой аргумент related_name полезен для полей ManyToManyField и ForeignKey ? Например, учитывая следующий код, каков эффект related_name=’maps’ ?
5 ответов
Атрибут related_name указывает имя обратного отношения от модели User к вашей модели.
Если вы не укажете related_name , Django автоматически создаст его, используя имя вашей модели с суффиксом _set , например User.map_set.all() .
Если вы делаете , укажите, например, related_name=maps в модели User , User.map_set все еще будет работать, но синтаксис User.maps. , очевидно, немного чище и менее неуклюж; например, если у вас есть объект пользователя current_user , вы можете использовать current_user.maps.all() , чтобы получить все экземпляры вашей модели Map , имеющие отношение к current_user .
В документации Django есть больше подробностей.
prefetch_related используется для данных предварительной выборки для данных отношения Многие ко многим и многие к одному. select_related предназначен для выбора данных из отношения с одним значением. Оба они используются для извлечения данных из их отношений из модели. Например, вы строите модель и модель, которая связана с другими моделями. Когда приходит запрос, вы также запрашиваете данные об их отношениях, и у Django есть очень хорошие механизмы для доступа к данным из их отношений, например, book.author.name , но когда вы повторяете список моделей для извлечения данных об их отношениях Django создает каждый запрос для каждого отдельного отношения данных. Чтобы преодолеть это, у нас есть prefetchd_related и selected_related
Добавление к существующему имени, связанного с ответом, является обязательным, если в модели 2 FK, указывающих на одну и ту же таблицу. Например, в случае спецификации
Поэтому, когда вам нужно будет получить доступ к этим данным, вы можете использовать только связанное имя
Это не работает иначе (по крайней мере, я не смог пропустить использование связанного имени в случае 2 FK для одной таблицы.)
Аргумент related_name также полезен, если у вас есть более сложные связанные имена классов. Например, если у вас есть отношение внешнего ключа:
Лучшие практики работы с моделями Django на Python
Перевод статьи «Best practices working with Django models in Python».
Photo by Thomas McPherson on Unsplash
1. Правильные имена моделей
Как правило, в качестве имён моделей рекомендуется использовать существительные в единственном числе, например: User , Post , Article . Существительным должно быть именно последнее слово в названии, например Some New Shiny Item . Использование единственного числа корректно, когда единица модели не содержит информацию о нескольких объектах сразу.
2. Названия полей, задающих отношения
Для таких отношений, как ForeignKey , OneToOneKey , ManyToMany лучше указывать более специфичное имя.
Представьте, что существует модель с названием Article , в которой помимо всего прочего определено отношение ForeignKey для модели User . Если это поле содержит информацию об авторе статьи, то имя author подойдёт куда лучше, чем просто user .
3. Правильное название для related-name
Атрибут related_name логичнее указывать во множественном числе, так как обращение по этому имени возвращает набор запросов (queryset). Не поленитесь – дайте ему осмысленное имя. В большинстве случаев подходящий вариант для related_name — имя модели во множественном числе. Например:
4. Не используйте ForeignKey с параметром unique=True
Нет смысла использовать unique=True в отношениях ForeignKey : для таких случаев есть OneToOneField .
5. Порядок атрибутов и методов в модели
Предпочтительно описывать атрибуты и методы модели в следующем порядке:
- константы (choices и т.д.)
- поля модели
- задание custom managers
- meta
- def __unicode__ (python 2) или def __str__ (python 3)
- другие специальные методы
- def clean
- def save
- def get_absolut_url
- остальные методы
Обратите внимание, что данная последовательность была взята из документации и немного дополнена.
6. Добавление модели через миграцию
Если требуется добавить модель, то после создания класса модели выполните команды manage.py (в указанном порядке): makemigrations и migrate (или используйте South для Django версии 1.6 и ниже).
7. Денормализация
Не допускайте бездумное использование денормализации в реляционных базах данных. Всегда старайтесь этого избегать, за исключением случаев осознанного применения денормализации данных для каких бы то ни было целей (например, ради производительности).
Если на стадии разработки БД вы понимаете, что придется денормализовать слишком много данных, может быть, правильным решением было бы использование NoSQL. Однако, если большинство данных этого не требует, задумайтесь о хранении части данных в реляционной БД с JsonField .
8. BooleanField
Не используйте null=True или blank=True для BooleanField . Также отметим, что для таких полей лучше указывать значения по умолчанию. Если вы понимаете, что поле всё же может остаться пустым, вам понадобится NullBooleanField .
9. Бизнес-логика в моделях
Лучшее место для размещения бизнес-логики проекта — это модели, а именно методы и менеджеры моделей. Возможно, некоторые методы будут только вызывать какие-нибудь методы/функции.
Если поместить логику в модели неудобно или вовсе невозможно, вам стоит заменить относящиеся к ней формы или сериализаторы в тасках (tasks).
10. Дублирование полей в ModelForm
Не следует без надобности дублировать поля моделей в ModelForm или ModelSerializer . Если вы хотите указать, что форма использует все поля моделей, используйте MetaFields .
Если вам нужно переопределить виджет поля так, чтобы всё остальное в этом поле осталось неизменным, используйте Meta widgets для указания виджетов.
11. Не используйте ObjectDoesNotExist
Указание ModelName.DoesNotExist вместо ObjectDoesNotExist сделает обработку исключений более специализированной, что является хорошей практикой.
12. Использование choices
При использовании choices рекомендуют придерживаться следующих правил:
- Хранить в БД строки, а не числа. Хотя это не лучший выход с точки зрения использования необязательных данных, на практике это оказывается удобнее, так как строки более наглядны. Это позволяет использовать понятные фильтры для получения вариантов из полей в REST-фреймворках.
- Переменные для хранения вариантов являются константами. Поэтому они должны быть указаны в верхнем регистре.
- Указывать варианты перед списками полей.
- При описании списка состояний указывать его нужно в хронологическом порядке (например: new , in_progress , completed ).
- Можно использовать Choices из библиотеки model_utils . Возьмём, к примеру, модель Article :
13. Зачем нужны лишние .all()?
При использовании ORM нет необходимости дополнительно вызывать метод all перед filter() , count() , и т.д.
14. В модели много флагов?
Если это оправдано, замените несколько BooleanFields одним полем статуса. Пример:
Пусть логика нашего приложения предполагает, что статья изначально не опубликована и не проверена. Затем она проверяется и помечается: is_verified становится True , а затем публикуется.
Как можно заметить, статью нельзя опубликовать непроверенной. Поэтому всего у нас есть 3 состояния. При наличии двух булевых полей получается 4 возможных состояния, которых у нас в реальности нет. Поэтому придётся делать проверки, чтобы не допустить наличия статей с неверными сочетаниями булевых полей. Вот почему использование одного поля статуса вместо двух логических переменных – лучшее решение:
Этот пример может быть не очень показательным, но представьте, что в вашей модели 3 или более таких логических переменных. Отслеживание сочетаний всех таких полей может действительно утомить.
15. Имя модели в названиях полей – многословность
Не добавляйте имена моделей в названия полей: в этом нет необходимости. Например, если таблица User имеет поле user_status – лучше переименовать его в status (при условии, что других полей со статусами в данной модели нет).
Photo by Teer XC on Unsplash
16. Избегайте «грязных» данных в базе
Всегда следует использовать PositiveIntegerField вместо IntegerField , если в этом есть смысл, потому что в базу не должны попадать «грязные» данные.
По той же причине всегда следует использовать unique , unique_together для данных, которые логично сделать уникальными, и никогда не ставить required=False во всех полях подряд.
17. Получение первого/последнего объекта
Вместо order_by(‘created’)[0] можно использовать ModelName.objects.earliest(‘created’/’earliest’) , а ещё можно применять get_latest_by в модели Meta. Помните, что latest/earliest так же, как и get , могут вызывать исключение DoesNotExist . Таким образом, order_by(‘created’).first() – самый полезный вариант.
18. Никогда не пользуйтесь len(queryset)
Не прибегайте к методу len , если хотите узнать количество объектов в queryset . Для этих целей может быть вызван метод count .
Если же делать так: len(ModelName.objects.all()) , сначала будет выполнен запрос на выбор всех данных из таблицы, затем эти данные будут преобразованы в Python-объект, и только потом длина этого объекта будет найдена с помощью len . Использовать такой подход крайне не рекомендуется, поскольку в случае с count произойдёт лишь обращение к SQL-функции COUNT() . При выполнении count будет обработан более простой запрос в той же базе данных и будет потрачено куда меньше ресурсов для исполнения кода на Python.
19. if queryset – плохая идея
Не используйте queryset в качестве логического значения – вместо if queryset: сделать что-то используйте if queryset.exists(): сделать что-то .
Помните, что наборы запросов очень ленивые, и если вы используете queryset как булево значение, в БД будет выполнен неприемлемый запрос.
20. Использование help_text для документации
Используйте help_text в полях модели как часть документации. Это определённо облегчит понимание структуры данных для вас, ваших коллег и пользователей-администраторов.
21. Хранение информации о деньгах
Не стоит использовать FloatField для хранения данных о количестве денег. Вместо этого можно прибегнуть к классу DecimalField . Вы можете также хранить эту информацию в центах, единицах, и т.д.
22. Не применяйте null=true, если это не нужно
null=True – позволяет столбцу БД хранить значение null.
blank=True – будет использовано только в формах для валидации и не относится к базе данных. В текстовых полях лучше хранить значение default.
Так вы получите только одно возможное значение для столбцов без данных.
23. Избавьтесь от _id
Не нужно добавлять суффикс _id к ForeignKeyField и OneToOneField .
24. Определяйте __unicode__ или __str__
Во всех неабстрактных моделях добавляйте методы __unicode__ (python 2) или __str__ (python 3). Эти методы должны всегда возвращать строки.
25. Прозрачный список полей
Не используйте Meta.exclude для описания списка полей в ModelForm . Для этого больше подходит Meta.fields , так как он делает этот список понятным. По той же причине не стоит применять Meta.fields=”__all__” .
26. Не сваливайте все загруженные пользователем файлы в одну папку
Порой, если ожидается большое количество скачиваний файлов, даже отдельной папки для каждого FileField будет недостаточно. Хранение множества файлов в одной папке означает, что система будет искать требуемый файл дольше. Во избежание такой ситуации можно сделать следующее:
27. Используйте абстрактные модели
Если вы хотите, чтобы модели разделяли какую-то логику, можно воспользоваться абстрактными моделями.
28. Используйте custom Manager и наборы запросов
Чем больше проект, над которым вы работаете, тем больше кода повторяется в разных его местах.
Чтобы не отходить от принципа DRY и размещать в моделях бизнес-логику, можно использовать custom Managers и Queryset .
Вот пример. Если требуется получить количество комментариев к постам из примера выше:
Можно использовать следующее:
Если нужно применить этот метод в связке с другими методами queryset , следует использовать CustomQuerySet :
Для чего в Django используется `related_name`?
В чём related_name аргумент полезен для ManyToManyField и ForeignKey поля? Например, учитывая следующий код, каков эффект related_name=’maps’ ?
@DanielRoseman Каким-то образом полезно для производительности или хорошей практики использовать related_name = ‘+’, когда обратное отношение не требуется? — lajarre
Мне было бы интересно узнать ответ на вопрос @lajarre. — 3cheesewheel
@lajarre — я предполагаю, что это никак не повлияет на производительность. Однажды мне пришлось использовать его с типами контента FeinCMS. Я лично считаю хорошей практикой всегда указывать related_name так что, если вы знаете, что не будете его использовать, я думаю, это хорошо. Конечно, это личное мнение. — François Constant
@ 3cheesewheel сейчас в документации: docs.djangoproject.com/en/2.0/ref/models/fields/… + значит не создавать обратной связи — Myer
6 ответы
related_name атрибут определяет имя обратной связи из User модель обратно к вашей модели.
Если вы не укажете related_name , Django автоматически создает модель, используя имя вашей модели с суффиксом _set , например User.map_set.all() .
если ты do указать, например related_name=maps на User модели, User.map_set все равно будет работать, но User.maps. синтаксис, очевидно, немного чище и менее громоздок; так, например, если у вас есть пользовательский объект current_user , вы могли бы использовать current_user.maps.all() получить все экземпляры вашего Map модель, имеющая отношение к current_user .
Документация Django есть более подробная информация.
Хорошо, я знаю, что это старый пост. Но я просто пытаюсь понять это — что за трюк + в конце родственного имени? Например, что будет, если я related_name=’maps+’ в примере выше? — Sidd
если вы добавите +, django отключит отображение — Josephmisiti
для OneToOneField по умолчанию related_name будет маленьким именем класса case. Например, в данном примере, если членами будут OneToOnefield, то «User.map» будет работать. — ширина
если вы укажете related_name делает _set все еще работаю в django1.11 > ?? — Эсир Кингс
Я использую Django 2.1.3, и я могу отметить, что они эксклюзивны. Один раз related_name указано, _set больше не работает. — Штокерский
Добавление к существующему имени, относящемуся к ответу, является обязательным, если в модели есть 2 FK, которые указывают на одну и ту же таблицу. Например, в случае ведомости материалов
Поэтому, когда вам нужно будет получить доступ к этим данным, вы можете использовать только связанное имя
В противном случае он не работает (по крайней мере, я не смог пропустить использование связанного имени в случае 2 FK в одной таблице.)
ответ дан 28 апр.

Вы должны выбрать related_name хотя бы для одного из них. Другой не требует. — Чаба Тот
related_name должно быть во множественном числе. Поскольку отношения ForeignKey возвращают несколько объектов. — Месут Ташчи
извините за публикацию некро =) Комментарий Месута заслуживает внимания. примером того, что они упоминают, может быть класс Employee (models.Model): manager = models.ForeignKey (‘self’, related_name = ‘manages’, on_delete = models.CASCADE, blank = False, null = False) google: » Советы Django № 22 «Создание лучших моделей» для получения дополнительной информации — кабан
related_name Аргумент также полезен, если у вас есть более сложные имена связанных классов. Например, если у вас есть отношения внешнего ключа:
Чтобы получить доступ UserMapDataFrame объекты из связанных User , вызов по умолчанию будет User.usermapdataframe_set.all() , который довольно сложно читать.
Посмотрите на график related_name позволяет вам указать более простое или более разборчивое имя, чтобы получить обратную связь. В этом случае, если вы укажете user = models.ForeignKey(User, related_name=’map_data’) , тогда звонок будет User.map_data.all() .
ответ дан 13 дек ’18, 16:12

Суть вашего вопроса заключается в следующем.
Так как у вас есть Map и User модели и вы определили ManyToManyField в модели карты, если вы хотите получить доступ к члены карты, то у вас есть возможность map_instance.members.all() поскольку вы определили члены поле. Тем не менее, если вы хотите получить доступ ко всем картам, пользователь является частью того, какой вариант у вас есть.
По умолчанию Django предоставил вам user_instance.modelname_set.all() и это переведет на user.map_set.all() в этом случае.
карты намного лучше, чем набор_карт.
связанное_имя предоставляет вам возможность сообщить Django, как вы собираетесь получить доступ к карте из пользовательской модели или в целом, как вы можете получить доступ к обратным моделям, что составляет весь смысл создания полей ManyToMany и использования ORM в этом смысле.