Пытаемся отфильтровать поле "менеджеры", чтобы оно показывало только менеджеров в отделе пользователя, вошедшего в систему в данный момент
У меня есть 3 модели
Базовая модель пользователя, которую предоставляет Django
UserProfile, модель, которая имеет 2 поля: поле внешнего ключа с таблицей пользователей поле department, которое является полем выбора с выпадающим меню, каждый пользователь имеет 1 отдел
.
И, наконец, модель данных, содержащая поле Manager, во многом совпадающее с моделью пользователя.
Модели
class Data(models.Model):
"""Model representing each event's data."""
title = models.CharField(max_length=200)
description = models.TextField(max_length = 2000)
managers = models.ManyToManyField(User, related_name = "event_co_manager_user", blank=True)
class UserProfile(models.Model):
"""Model representing the user profile"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
DEPARTMENT_CHOICES = (
(0, 'Dep1'),
(1, 'Dep2'),
(2, 'Dep3'),
)
department = models.PositiveSmallIntegerField(choices=DEPARTMENT_CHOICES, null=True)
Я пытаюсь отфильтровать поле менеджера на бэкенде, чтобы показывать только менеджеров, которые работают в одном отделе, поскольку мы не хотим, чтобы люди могли добавлять другие отделы в качестве менеджеров в свои события
Вот функция, которую я пытаюсь перезаписать в моем admin.py (использую Django 5.0)
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "managers":
kwargs["queryset"] = Data.objects.filter(managers.userprofile.department == request.user.userprofile.department)
return super().formfield_for_manytomany(db_field, request, **kwargs)
Я продолжаю получать ошибки о том, что поле managers не имеет атрибута userprofile
Когда вы хотите построить запрос, который будет расширять отношения, например, когда вы хотите отфильтровать по атрибуту ForeignKey
, вам нужно использовать dunder вместо period для доступа к этим отношениям.
Заменить:
Data.objects.filter(managers.userprofile.department ==
с:
Data.objects.filter(managers__userprofile__department ==
Вы можете установить queryset с помощью:
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == 'managers':
kwargs['queryset'] = Data.objects.filter(
managers__userprofile__department=request.user.userprofile.department
)
return super().formfield_for_manytomany(db_field, request, **kwargs)
but this will make an extra query to get the .userprofile
of the request.user
. Additionally using choices=…
[Django-doc] for something that can "grow" is often not a good idea.
Обычно используется дополнительная модель, например:
class Data(models.Model):
"Model representing each event's data."
title = models.CharField(max_length=200)
description = models.TextField(max_length=2000)
managers = models.ManyToManyField(
User, related_name='event_co_manager_user', blank=True
)
class Department(models.Model):
name = models.CharField(max_length=128, unique=True)
def __str__(self):
return self.name
class UserProfile(models.Model):
'Model representing the user profile'
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.ForeignKey(
Department,
on_delete=models.PROTECT,
related_name='userprofiles',
null=True,
)
Тогда это выглядит так:
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == 'managers':
kwargs['queryset'] = Data.objects.filter(
managers__userprofile__department__userprofile__user=request.user
)
return super().formfield_for_manytomany(db_field, request, **kwargs)