Для чего используется `related_name` в Django?

392

Какой related_nameаргумент полезен для полей on ManyToManyFieldи ForeignKey? Например, с учетом следующего кода, каков эффект related_name='maps'?

class Map(db.Model):
    members = models.ManyToManyField(User, related_name='maps',
                                     verbose_name=_('members'))
zjm1126
источник
12
@DanielRoseman Хорошо ли для производительности или хорошей практики использовать related_name = '+', когда обратное отношение не нужно?
Ладжарре
10
Мне было бы интересно узнать ответ на вопрос @ lajarre.
колесное колесо
1
@lajarre - я предполагаю, что это не изменит производительность вообще. Мне приходилось использовать его один раз с типами контента FeinCMS. Я лично думаю, что это хорошая практика - всегда указывать, related_nameтак что, если вы знаете, что не будете его использовать, я думаю, это хорошо. Это личное мнение, конечно.
Франсуа Констант
@ 3cheesewheel теперь в документации: docs.djangoproject.com/en/2.0/ref/models/fields/… + означает, что не создавать обратную связь
P. Myer Nore

Ответы:

532

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 есть больше деталей.

Воган
источник
1
Хорошо, я знаю, что это старый пост. Но я просто пытаюсь понять это - что за хитрость + в конце названия? Например, что произойдет, если я сделал related_name='maps+'в примере выше?
Сидд
10
если вы добавите +, django отключит отображение
josephmisiti
5
для OneToOneField по умолчанию значение related_name будет именем класса малого регистра. Например, в данном примере, если члены будут OneToOnefield, тогда будет работать «User.map».
анчо
если вы укажете related_name, все _setеще работает в django1.11 >??
Эсир Кингс
9
Я использую Django 2.1.3 и могу отметить, что они эксклюзивны. Один раз related_nameуказан, _setбольше не работает.
Stockersky
85

Добавить к существующему ответу связанное имя обязательно, если в модели 2 FK, указывающих на одну и ту же таблицу. Например, в случае спецификации

@with_author 
class BOM(models.Model): 
    name = models.CharField(max_length=200,null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    tomaterial =  models.ForeignKey(Material, related_name = 'tomaterial')
    frommaterial =  models.ForeignKey(Material, related_name = 'frommaterial')
    creation_time = models.DateTimeField(auto_now_add=True, blank=True)
    quantity = models.DecimalField(max_digits=19, decimal_places=10)

Поэтому, когда вам нужно будет получить доступ к этим данным, вы можете использовать только связанное имя

 bom = material.tomaterial.all().order_by('-creation_time')

Это не работает иначе (по крайней мере, я не смог пропустить использование связанного имени в случае 2 FK для одной таблицы.)

Илья Бибик
источник
2
Вы должны выбрать related_name хотя бы для одного из них. Другой не требует.
Чаба Тот
32
related_nameдолжно быть во множественном числе. Потому что отношения ForeignKey возвращают несколько объектов.
Месут Таски
11

related_nameАргумент также полезно , если у вас есть более сложные родственные имена классов. Например, если у вас есть отношение внешнего ключа:

class UserMapDataFrame(models.Model):
    user = models.ForeignKey(User) 

Для доступа к UserMapDataFrameобъектам из связанных User, вызов по умолчанию будетUser.usermapdataframe_set.all() , который довольно сложно прочитать.

Использование related_nameпозволяет вам указать более простое или более разборчивое имя, чтобы получить обратную связь. В этом случае, если вы укажете user = models.ForeignKey(User, related_name='map_data'), вызов будет User.map_data.all().

Даниэль Холмс
источник
3

Связанный параметр имени на самом деле является опцией. Если мы не установим его, Django автоматически создаст для нас другую сторону отношения. В случае модели Map, Django создал бы map_setатрибут, разрешающий доступ via m.map_setв вашем примере (m является вашим экземпляром класса). Формула, которую использует Django, - это название модели, за которым следует строка _set. Таким образом, связанный параметр имени просто переопределяет стандартное значение Django, а не обеспечивает новое поведение.

Abrar
источник
0

prefetch_relatedиспользовать для предварительной выборки данных для данных «многие ко многим» и «многие к одному». select_relatedэто выбрать данные из одного значения отношения. Оба они используются для извлечения данных из их отношений из модели. Например, вы строите модель и модель, которая связана с другими моделями. Когда приходит запрос, вы также запрашиваете данные об их отношениях, и у Django есть очень хорошие механизмы для доступа к данным из их отношений, например, book.author.nameно когда вы выполняете итерацию списка моделей для извлечения данных об их отношениях, Django создает каждый запрос для каждой отдельной информации об отношениях. Чтобы преодолеть это у нас есть prefetchd_relatedиselected_related

Джамиль Нойда
источник