Django:m2m 关系创建两行而不是一行

Django : m2m relationship create two line instead of one

我以这种方式扩展了 UserModel :

# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    # add additional fields in here
    credit = models.IntegerField(default=200)
    follow = models.ManyToManyField('self', related_name='follow')
    def __str__(self):
        return self.username

但我不知道应该如何 add/remove 一个追随者。我创建了一个视图:

@login_required
def follow(request, user_id):
    user = get_object_or_404(CustomUser, pk=user_id)
    if CustomUser.objects.filter(follow=user.pk).exists():
        request.user.follow.remove(user)
    else:
        request.user.follow.add(user)
    return redirect('profil', user_id)

问题:

假设 request.user.pk 是 1,user_id 是 2。

对于 add 部分(在 else 中),我希望数据库中有一个新行 from_customuser_id=1to_customuser_id=2 但是,它创建了两行:

对于 remove 部分(在 if 中),我希望它只删除行

但是它删除了这两行。

我阅读了 doc about django models relations 但没有找到解决此问题的方法。

问题:

我应该如何更新我的代码才能让 add 方法只插入一行,from_customuser_id=1from_customuser_id=2remove 方法只删除这一行(假设当前用户的 ID 为 1)。


不确定它是否相关,但为了完整起见,这是我 urls.py 的相关部分:

path('follow/<int:user_id>', views.follow, name='follow'),
path('unfollow/<int:user_id>', views.follow, name='unfollow'),

这就是我在模板中对它们的称呼:

{% if follow %}
    <a href="{% url 'follow' user_profil.id %}">
        Unfollow {{ user_profil.username }}
    </a>
{% else %}
    <a href="{% url 'unfollow' user_profil.id %}">
        Follow {{ user_profil.username }}
    </a>
{% endif %}

当您拥有 ManyToManyField 时,它实际上会在两个对象之间创建关系。这也允许您进行反向查找。

例如:

class Person(models.Model):
    name = model.CharField(max_length=100)

class Pet(models.Model):
    owners = models.ManyToMany(Person, related_name="pets")
    name = model.CharField(max_length=100)

bob = Person.objects.create(name="Bob")
john = Person.objects.create(name="John")
kitty_kat = Pet.objects.create(name="Kitty Kat")
kitty_kat.owners.set([bob, john])

根据这些模型,一只宠物可以被多人拥有,一个人可以拥有多只宠物。所以如果我这样做

bob.pets.all()          # I get kitty kat
kitty_kay.owners.all()  # I get bob & john

当这种关系应该在同一个模型上时,您最终会创建两个关系。一只为正装,一只为反装。

例如:

class Person(models.Model):
    name = model.CharField(max_length=100)
    followers = models.ManyToManyField('self', related_name='follow') 

bob = Person.objects.create(name="Bob")
john = Person.objects.create(name="John")
john.followers.add(bob)

bob.follow.all()       # I get john... notice I use follow and not followers
john.followers.all()   # I get bob

为了避免这种情况,您可以将 symmetrical=False 传递给该字段,然后将创建一行

followers = models.ManyToManyField('self', related_name='+', symmetrical=False)

related_name 设置为任何以 + 开头的内容也将阻止反向查找(在这种情况下不需要)