将对象添加到多对多字段的问题
Problem with adding objects to manytomany fields
我有一个用户模型:
class User(AbstractUser):
followers_num = models.IntegerField(default=0)
followings_num = models.IntegerField(default=0)
followers = models.ManyToManyField('self', blank=True, symmetrical=False)
followings = models.ManyToManyField('self', blank=True, symmetrical=False)
adding/removing 个用户对象的视图来自 followers/followings:
def follow(request, follow, user):
if (request.method == 'PUT'):
following_user = User.objects.get(username=user)
follower_user = User.objects.get(username=request.user.username)
if follow:
# Follow
following_user.followers.add(follower_user)
following_user.followers_num += 1
follower_user.followings.add(following_user)
follower_user.followings_num += 1
else:
# Unfollow
following_user.followers.remove(follower_user)
following_user.followers_num -= 1
follower_user.followings.remove(following_user)
follower_user.followings_num -= 1
following_user.save()
follower_user.save()
return HttpResponse(status=204)
我想让它添加 follower_user
到 following_user
的关注者,并将 following_user
添加到 follower_user
的关注者。但是,它没有这样做,而是将 follower_user
不仅添加到 following_user
的关注者中,而且还将其添加到 following_user
的关注者中。为什么会这样?
编辑:
我将 symmetrical=False
添加到字段,但这导致了错误:
SystemCheckError: System check identified some issues:
ERRORS:
network.User.followers: (fields.E304) Reverse accessor for 'network.User.followers' clashes with reverse accessor for 'network.User.followings'.
HINT: Add or change a related_name argument to the definition for 'network.User.followers' or 'network.User.followings'.
network.User.followings: (fields.E304) Reverse accessor for 'network.User.followings' clashes with reverse accessor for 'network.User.followers'.
HINT: Add or change a related_name argument to the definition for 'network.User.followings' or 'network.User.followers'.
使用这个作为你的模型:
class User(AbstractUser):
followers_num = models.IntegerField(default=0)
followings_num = models.IntegerField(default=0)
followers = models.ManyToManyField('self', related_name='followings', null=True, blank=True)
这利用了 Willem 提到的 symmetrical 逻辑。这将避免您必须跟踪两个 ManyToManyFields 中的关系。
However, instead of doing so, it adds follower_user not only to the followers
of following_user
, but it also adds it to the followings
of following_user
. Why does it happen?
因为 Django 与 self
的关系默认是对称的。您应该通过设置 symmetrical=False
[Django-doc] 使关系不对称,只需使用 one ManyToManyField
,所以:
class User(AbstractUser):
followers = models.ManyToManyField(
'self',
blank=True,
<strong>symmetrical=False</strong>,
<strong>related_name='following'</strong>
)
逻辑很简单:
from django.shortcuts import get_object_or_404
def follow(request, follow, user):
if request.method == 'PUT':
following_user = get_object_or_404(User, username=user)
follower_user = request.user
if follow:
following_user.followers.add(follower_user)
else:
following_user.followers.remove(follower_user)
return HttpResponse(status=204)
如果用户 A 在 B 的 .followers
中,则 B自动在A的.following
中,所以不需要使用两个关系
此外,您不必跟踪关注者的数量,必要时可以使用 .annotate(…)
[Django-doc] 进行统计。
Note: It is often better to use get_object_or_404(…)
[Django-doc],
then to use .get(…)
[Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…)
will result in returning a HTTP 404 Not Found response, whereas using
.get(…)
will result in a HTTP 500 Server Error.
我有一个用户模型:
class User(AbstractUser):
followers_num = models.IntegerField(default=0)
followings_num = models.IntegerField(default=0)
followers = models.ManyToManyField('self', blank=True, symmetrical=False)
followings = models.ManyToManyField('self', blank=True, symmetrical=False)
adding/removing 个用户对象的视图来自 followers/followings:
def follow(request, follow, user):
if (request.method == 'PUT'):
following_user = User.objects.get(username=user)
follower_user = User.objects.get(username=request.user.username)
if follow:
# Follow
following_user.followers.add(follower_user)
following_user.followers_num += 1
follower_user.followings.add(following_user)
follower_user.followings_num += 1
else:
# Unfollow
following_user.followers.remove(follower_user)
following_user.followers_num -= 1
follower_user.followings.remove(following_user)
follower_user.followings_num -= 1
following_user.save()
follower_user.save()
return HttpResponse(status=204)
我想让它添加 follower_user
到 following_user
的关注者,并将 following_user
添加到 follower_user
的关注者。但是,它没有这样做,而是将 follower_user
不仅添加到 following_user
的关注者中,而且还将其添加到 following_user
的关注者中。为什么会这样?
编辑:
我将 symmetrical=False
添加到字段,但这导致了错误:
SystemCheckError: System check identified some issues:
ERRORS:
network.User.followers: (fields.E304) Reverse accessor for 'network.User.followers' clashes with reverse accessor for 'network.User.followings'.
HINT: Add or change a related_name argument to the definition for 'network.User.followers' or 'network.User.followings'.
network.User.followings: (fields.E304) Reverse accessor for 'network.User.followings' clashes with reverse accessor for 'network.User.followers'.
HINT: Add or change a related_name argument to the definition for 'network.User.followings' or 'network.User.followers'.
使用这个作为你的模型:
class User(AbstractUser):
followers_num = models.IntegerField(default=0)
followings_num = models.IntegerField(default=0)
followers = models.ManyToManyField('self', related_name='followings', null=True, blank=True)
这利用了 Willem 提到的 symmetrical 逻辑。这将避免您必须跟踪两个 ManyToManyFields 中的关系。
However, instead of doing so, it adds follower_user not only to the
followers
offollowing_user
, but it also adds it to thefollowings
offollowing_user
. Why does it happen?
因为 Django 与 self
的关系默认是对称的。您应该通过设置 symmetrical=False
[Django-doc] 使关系不对称,只需使用 one ManyToManyField
,所以:
class User(AbstractUser):
followers = models.ManyToManyField(
'self',
blank=True,
<strong>symmetrical=False</strong>,
<strong>related_name='following'</strong>
)
逻辑很简单:
from django.shortcuts import get_object_or_404
def follow(request, follow, user):
if request.method == 'PUT':
following_user = get_object_or_404(User, username=user)
follower_user = request.user
if follow:
following_user.followers.add(follower_user)
else:
following_user.followers.remove(follower_user)
return HttpResponse(status=204)
如果用户 A 在 B 的 .followers
中,则 B自动在A的.following
中,所以不需要使用两个关系
此外,您不必跟踪关注者的数量,必要时可以使用 .annotate(…)
[Django-doc] 进行统计。
Note: It is often better to use
get_object_or_404(…)
[Django-doc], then to use.get(…)
[Django-doc] directly. In case the object does not exists, for example because the user altered the URL themselves, theget_object_or_404(…)
will result in returning a HTTP 404 Not Found response, whereas using.get(…)
will result in a HTTP 500 Server Error.