Django + Django Rest Framework: получение корректных связанных объектов на промежуточной модели
У меня есть промежуточная модель со следующими полями:
class UserSkill(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
skill = models.ForeignKey(Skill, on_delete=models.CASCADE, related_name='user_skills')
disabled = models.BooleanField(default=False)
Как вы можете видеть, она имеет два внешних ключа, один к пользователю auth, а другой к другой таблице под названием skill.
Я пытаюсь получить все навыки, назначенные определенному пользователю, поэтому я делаю следующее get_queryset в моем ViewSet:
class AssignedSkillViewSet(viewsets.ModelViewSet):
queryset = Skill.objects.all()
serializer_class = AssignedSkillSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user
return Skill.objects.filter(user_skills__user=user, user_skills_user__disabled=False))
Теперь мне также нужно включить информацию о промежуточной модели в API, к которой я могу получить доступ через users_skills связанное имя в сериализаторе DRF, следующим образом:
class AssignedSkillSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Skill
fields = [
'id',
'url',
'title',
'description',
'user_skills',
]
Но когда я пытаюсь получить эту информацию, она возвращает ALL user_skills, связанные с назначенным навыком, независимо от того, назначены ли они другим пользователям. Мне нужна информация о связанной модели только для этого пользователя и этого навыка.
Например: Если у меня есть навык под названием Математика, и пользователь под названием Мария
related_skills = Skill.objects.filter(user_skills__user=user, user_skills_user__disabled=False)).user_skills.all()
<
[
<UserSkill: Math+Jenniffer>,
<UserSkill: Math+Gabriel>,
<UserSkill: Math+John>,
<UserSkill: Math+Maria>,
]
Приведенный выше код вернет:
Мне нужно получить только предмет <UserSkill: Math+Maria>. Список никак не упорядочен, поэтому получение последнего элемента в списке работает не во всех случаях.
Я знаю, что есть что-то, что я, вероятно, упускаю. Я ценю любую помощь или подсказки, которые вы можете мне дать.
Я думаю, что когда вы делаете фильтр:
Skill.objects.filter(
user_skills__user=user, #condition_1
user_skills_user__disabled=False, #condition_2
).user_skills.all()
Вы уже выполнили запрос, относящийся к модели UserSkill
. Потому что фильтр выполняется в модели Skill
, а #condition_1 (user_skills__user=user
) использует информацию из модели UserSkill
для фильтрации по пользователям. Но когда вы делаете .user_skills.all()
в конце запроса, вы перекрываете фильтр всеми данными из модели UserSkill.
Чтобы получить список экземпляров UserSkill из фильтра, вы можете попробовать:
UserSkill.objects.filter(
user="Maria",
skill="Math",
)
Возможно, это поможет
.
serializers.py
class SkillSerializer(serializers.ModelSerializer):
class Meta:
model = Skill
fields = ['id', ...]
class UserSkillSerializer(serializers.ModelSerializer):
skill_detail = SkillSerializer(many=True)
class Meta:
model = UserSkill
fields = ['id', 'user', 'skill_detail']
views.py
class AssignedSkillViewSet(viewsets.ModelViewSet):
queryset = UserSkill.objects.all()
serializer_class = UserSkillSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user
return UserSkill.objects.filter(user=user, disabled=False))
В этом случае вам нужно использовать объект Prefetch
...[Django-doc] с пользовательским кверисетом, который использует те же фильтры, что и ваш основной кверисет, вот так:
from django.db.models import Prefetch
def get_queryset(self):
user = self.request.user
return Skill.objects.filter(
user_skills__user=user,
user_skills__user__disabled=False,
).prefetch_related(
"user_skills",
queryset=UserSkill.objects.filter(
user=user,
user__disabled=False,
)
)