Невозможно исключить внешние ключи в django
У меня не получается получить Profiles
без Interaction
. Кто-нибудь понимает, что я делаю не так?
#models.py
class Profile(models.Model):
username = models.CharField(max_length=100)
class Interaction(models.Model):
user_id = models.ForeignKey(Profile,on_delete=models.CASCADE, null=True, blank=True)
#test.py
class TestQueries(TestCase):
def test_get_profiles_without_interaction(self):
profile_with_interaction = Profile.objects.get(username='foobar')
interactions_from_profile = Interaction.objects.filter(
user_id=profile_with_interaction)
assert interactions_from_profile
#####FAILS#####
all_profiles_without_interaction = Profile.objects.exclude(
pk__in=Interaction.objects.all())
assert profile_with_interaction not in all_profiles_without_interaction
Дело в том, как вы исключаете профили! Когда вы используете pk__in=Interaction.objects.all()
, это должно быть pk__in=Interaction.objects.values_list('user_id', flat=True)
.
Так что теперь вы исключаете только те профили, к которым действительно привязаны взаимодействия.
all_profiles_without_interaction = Profile.objects.exclude(
pk__in=Interaction.objects.values_list('user_id', flat=True))
Исключить можно с помощью:
Profile.objects.filter(interaction=None)
Вы также можете ограничить опции для ModelForm
с помощью limit_choices_to=…
[Django-doc]:
class Interaction(models.Model):
user = models.ForeignKey(
Profile,
on_delete=models.CASCADE,
null=True,
blank=True,
limited_choices_to={'interaction': None},
)
В данном конкретном случае вы можете обеспечить это с помощью unique ForeignKey
: OneToOneField
model поле [Django-doc]:
class Interaction(models.Model):
user = models.OneToOneField(
Profile,
on_delete=models.CASCADE,
null=True,
blank=True,
)
Примечание: Обычно не добавляют суффикс
…_id
к полюForeignKey
, так как Django автоматически добавит поле-«близнец» с суффиксом…_id
. Поэтому он должен бытьuser
, вместо.user_id