How to delete from queryset without deleting the original model itself in Django

Viewed 648

So, I have two model sets like the following:

# User class
class User(AbstractBaseUser, PermissionsMixin):
    objects = CustomUserManager()
    ...
    email = models.EmailField(verbose_name='email', max_length=50, null=False, unique=True)
    password = models.CharField(verbose_name="password", max_length=200)
    name = models.CharField(verbose_name="name", max_length=50)
    username = models.CharField(verbose_name="nickname", max_length=50, unique=True)
    date_of_birth = models.DateField(verbose_name="birthday", max_length=8)
    profile_pic = models.ImageField(verbose_name="profile picture", default="default_profile.png")

    USERNAME_FIELD='email'
    REQUIRED_FIELDS=['password', 'name', 'username', 'date_of_birth']

    followers = models.ManyToManyField(
        'self',
        symmetrical=False,
        through='Relationship',
        related_name='followees',
        through_fields=('to_user', 'from_user'),
        )

    @property
    def followers(self):
        follower_relationship = self.relationship_to_user.filter(relationship_type=Relationship.RELATIONSHIP_TYPE_FOLLOWING)
        follower_list = follower_relationship.values_list('from_user', flat=True)
        followers = User.objects.filter(pk__in=follower_list)
        return followers

    @property
    def followees(self):
        followee_relationship = self.relationship_from_user.filter(relationship_type=Relationship.RELATIONSHIP_TYPE_FOLLOWING)
        followee_list = followee_relationship.values_list('to_user', flat=True)
        followees = User.objects.filter(pk__in=followee_list)
        return followees        
    
    def follow(self, to_user):
        self.relationship_from_user.create(
            to_user = to_user,
            relationship_type='f'
            )
    
    def __str__(self):
        return self.username
# Relationships class
class Relationship(models.Model):
    RELATIONSHIP_TYPE_FOLLOWING = 'f'
    RELATIONSHIP_TYPE_BLOCKED = 'b'
    CHOICE_TYPE = (
        (RELATIONSHIP_TYPE_FOLLOWING, '팔로잉'),
        (RELATIONSHIP_TYPE_BLOCKED, '차단'),
        )
    from_user = models.ForeignKey(
        User,
        related_name='relationship_from_user',
        on_delete=models.CASCADE,
        )
    to_user = models.ForeignKey(
        User,
        related_name='relationship_to_user',
        on_delete=models.CASCADE,
        )
    relationship_type=models.CharField(max_length=1, choices=CHOICE_TYPE)

    def __str__(self):
        return f"{self.from_user} follows {self.to_user}, type={self.relationship_type}"

And in the python manage.py shell, I did the following:

>>> user1 = User.objects.get(id=1)    # user1@gmail.com 
>>> user2 = User.objects.get(id=2)    # user2@gmail.com
>>> user3 = User.objects.get(id=3)    # user3@gmail.com
>>> user1.follow(user2)
>>> user1.follow(user3)
>>> user1.followees
<QuerySet [<User: user2@gmail.com>, <User: user3@gmail.com>]>

Now my main question is related to the user1.followees. I want to delete <User: user3@gmail.com> from the user1.followees queryset without deleting also the user from the database. I've tried the following:

>>> user1.followees[1].delete()                         # 1
>>> user1.followees.exclude(email='user3@gmail.com')    # 2

The first try(#1) does delete the user3 from the queryset, but also deletes the user itself from the database and prints outs the following (The print might not be the same when you do it because this is the third or fourth time I've been trying this on my own):

(4, {'accounts.Relationship': 3, 'accounts.User': 1})

The second try(#2) does exclude the designated user and returns a new queryset without the user, but the original queryset is not altered when I access it, as shown in the following:

>>> user1.followees.exclude(email='user3@gmail.com')
<QuerySet [<User: user2@gmail.com>]>
>>> user1.followees
<QuerySet [<User: user2@gmail.com>, <User: user3@gmail.com>]>
2 Answers

It seems that I was accessing the user itself from what I was doing:

>>> user1.followees[0] --> This accesses the user who's in the followees[0], not the relatioship itself

Therefore, when I try deleting the queryset, I'm accessing the user itself, so I'm actually deleting the queryset and the user itself. Therefore, my solution was to access the Relationship, not the user. I did the following:

>>> Relationship.objects.all()
<QuerySet [<Relationship: user1@gmail.com follows user2@gmail.com, type=f>, <Relationship: user1@gmail.com follows user3@gmail.com type=f>]>
>>> Relationship.objects.all()[0]
<QuerySet [<Relationship: user1@gmail.com follows user3@gmail.com, type=f>]>
>>> Relationship.objects.all()[0].delete()
(1, {'accounts.Relationship': 1})

and checking the Relationship model and the user1 relationship:

>>> Relationship.objects.all()
<QuerySet [<Relationship: user1@gmail.com follows user3@gmail.com type=f>]>
>>> user1.followees
>>> <QuerySet [<User: user2@gmail.com>]>

This was the answer!

** This method was possible, but the answer that @user1464664 gave is a much better one, so I suggest looking into that one

Related