Невозможно исключить внешние ключи в 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.

Вернуться на верх