如何在不删除 Django 中的原始模型本身的情况下从查询集中删除

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

所以,我有如下两个模型集:

# 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}"

并且在 python manage.py shell 中,我执行了以下操作:

>>> 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>]>

现在我的主要问题与 user1.followees 有关。我想从 user1.followees 查询集中删除 <User: user3@gmail.com> 而不同时从数据库中删除用户。我尝试了以下方法:

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

第一个 try(#1) 确实从查询集中删除了 user3,但也从数据库中删除了用户本身并打印出以下内容(打印出来的内容可能与您执行此操作时不同,因为这是第三次或第四次我一直在自己尝试这个):

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

第二次try(#2)确实排除了指定的用户,returns一个没有用户的新queryset,但是我访问的时候没有改变原来的queryset,如下图:

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

看来我正在访问用户本身:

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

因此,当我尝试删除查询集时,我正在访问用户本身,所以我实际上是在删除查询集用户本身。因此,我的解决方案是访问 Relationship,而不是用户。我做了以下事情:

>>> 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})

并检查关系模型和 user1 关系:

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

这就是答案!

** 这种方法是可行的,但是@user1464664 给出的答案要好得多,所以我建议研究一下那个

Manytomany 有添加和删除关系的特定方法。

user1.followees.remove(user3)

此外,除非您需要在 follow() 方法中自定义逻辑,否则您可以只使用 user1.followees.add(user3).

user1.followees.clear() 可以删除所有关注者。

https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/