Для чего используется параметр related_name?
Какова цель аргумента related_name
для полей ManyToManyField
и ForeignKey
? Например, в приведённом ниже коде каково воздействие related_name='maps'
?
class Map(db.Model):
members = models.ManyToManyField(User, related_name='maps',
verbose_name=_('members'))
5 ответ(ов)
Чтобы дополнить существующий ответ, стоит отметить, что использование related_name
обязательно в случае, если в модели есть два внешних ключа, указывающих на одну и ту же таблицу. Например, в случае с "Нормативной документацией":
@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)
Таким образом, когда вам потребуется получить доступ к данным, вы сможете использовать related_name
:
bom = material.tomaterial.all().order_by('-creation_time')
В противном случае обращение к данным не сработает (по крайней мере, у меня не получилось обойтись без использования related_name
, если есть два внешних ключа к одной таблице).
Аргумент 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()
.
Суть вашего вопроса такова.
У вас есть модели Map
и User
, и вы определили ManyToManyField
в модели Map
. Если вы хотите получить доступ к участникам карты, то вы можете использовать map_instance.members.all()
, так как вы определили поле members. Однако, если вам нужно получить все карты, в которых участвует пользователь, то каким образом вы можете это сделать?
По умолчанию Django предоставляет вам возможность использовать user_instance.modelname_set.all()
, и в вашем случае это будет user.map_set.all()
.
Тем не менее, использование maps будет предпочтительнее, чем использование map_set.
Поле related_name предоставляет вам возможность указать Django, как вы собираетесь получать доступ к модели Map
из модели User
, или, в общем, как вы можете получить доступ к обратным моделям. Это и является основной целью создания полей ManyToMany и использования ORM в таком контексте.
Параметр related_name
на самом деле является опциональным. Если мы его не укажем, Django автоматически создаст для нас обратную сторону отношения. В случае модели Map
, Django создаст атрибут map_set
, что позволит получить доступ через m.map_set
в вашем примере (где m
— это экземпляр вашего класса). Формула, которую использует Django, - это название модели, за которым следует строка _set
. Следовательно, параметр related_name
просто переопределяет значение по умолчанию, а не предоставляет новое поведение.
prefetch_related
используется для предварительной выборки данных в отношениях "многие ко многим" и "многие к одному". select_related
предназначен для выборки данных в отношениях с одним значением. Оба этих метода используются для получения данных из связанных моделей.
Например, вы создаете модель, которая имеет отношения с другими моделями. Когда поступает запрос, вам также нужно получить данные о связанных моделях. Django предоставляет отличные механизмы для доступа к данным из этих отношений, такие как book.author.name
. Однако, когда вы перебираете список объектов модели для получения их связанных данных, Django выполняет отдельный запрос для каждой связи, что может быть неэффективно.
Чтобы избежать этого, мы можем использовать prefetch_related
и select_related
. select_related
работает через JOIN и подходит для отношений "один к одному" и "многие к одному", в то время как prefetch_related
создает отдельные запросы и объединяет их на уровне Python, что делает его более подходящим для отношений "многие ко многим" и "многие к одному". Использование этих методов позволяет оптимизировать количество запросов к базе данных и ускорить работу приложения.
Существует ли список временных зон Pytz?
Как выполнить фильтрацию запросов в Django по условию "не равно"?
Превысил ли Django 100 тыс. посещений в день? [закрыто]
В чем разница между null=True и blank=True в Django?
Как отменить последнюю миграцию?