【问题标题】:Django : m2m relationship create two line instead of oneDjango:m2m关系创建两行而不是一行
【发布时间】:2019-05-08 11:25:36
【问题描述】:

我以这种方式扩展了 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

但我不知道应该如何添加/删除关注者。我创建了一个视图:

@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 但是,它会创建两行:

  • 符合预期的from_customuser_id=1from_customuser_id=2

  • 一个我不需要的 from_customuser_id=2from_customuser_id=1

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

  • from_customuser_id=1from_customuser_id=2

但它删除了这两行。

我阅读了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 %}

【问题讨论】:

    标签: django many-to-many django-orm


    【解决方案1】:

    当您拥有 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 设置为以+ 开头的任何内容也将阻止反向查找(在这种情况下您不需要)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-25
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多