[英]Multiple many-to-many relationships with a related_name of “+” result in the wrong query set
I have a Django model that has two many-to-many relationships to the auth.User
class, like: 我有一个Django模型,它与auth.User
类具有两个多对多关系,例如:
class Indicator(models.Model):
friends = models.ManyToManyField(User, related_name="+")
enemies = models.ManyToManyField(User, related_name="+")
The related_name is set to "+" so that there's no backwards relation , ie I don't need u.friends_set
and u.enemies_set
if u is a user. related_name设置为“ +”, 因此没有向后关系 ,即如果u是用户,则不需要u.friends_set
和u.enemies_set
。
Adding, removing, and clearing 'friends' and 'enemies' works fine - if I check directly in the database (ie not through Django) I can see the changes reflected as I would expect. 添加,删除和清除“朋友”和“敌人”可以正常工作-如果直接在数据库中检查(即不通过Django),则可以看到预期的变化。 However, if I get the query set through Django, I'm given the 'enemies' list whether I use i.friends.all()
or i.enemies.all()
(assuming i
is an Indicator instance). 但是,如果我通过Django获取查询集,则无论我使用i.friends.all()
还是i.enemies.all()
,都会获得“敌人”列表(假设i
是一个指标实例)。
If I examine the ManyRelatedManager, I see that the through
attribute is correct, which (if I understand correctly) is what allows add/remove/clear to work correctly: 如果我检查ManyRelatedManager,我会发现through
属性是正确的,(如果我理解正确的话)正是该属性允许添加/删除/清除功能正常工作:
>>> i.friends.through
<class 'project.app.models.Indicator_friends'>
However, the get_query_set
method basically gets the superclass (the User Manager) and calls filter on it with kwargs i.friends.core_filters
, which is {'+__pk': 404L}
(if the Indicator ID is 404). 但是, get_query_set
方法基本上获取超类(用户管理器),并使用kwargs i.friends.core_filters
调用过滤器,该过滤器为{'+__pk': 404L}
(如果指标ID为404)。 The core_filters are the same for both "friends" and "enemies", which explains why I incorrectly get the same query set for both. “朋友”和“敌人”的core_filters都是相同的,这解释了为什么我错误地为两者获取了相同的查询集。
I can work around this (without setting a related_name): instead of i.friends.all()
I can use: 我可以解决此问题(无需设置i.friends.all()
我可以使用i.friends.all()
代替:
[friend.user for friend in i.friends.through.objects.filter(indicator__id=i.id)]
However, that's hardly elegant. 但是,这并不优雅。
(Django 1.3 - I haven't tried trunk, but from reading the code it appears to have the same behaviour, with Python 2.7). (Django 1.3-我还没有尝试过主干,但是通过阅读代码,它似乎与Python 2.7具有相同的行为)。
Looking at django/db/models/fields/related.py, it appears that the related_name = '+' option is really tested with a last character string slice in ManyToOneRel.is_hidden(). 查看django / db / models / fields / related.py,看来related_name ='+'选项实际上是在ManyToOneRel.is_hidden()中使用最后一个字符串切片测试的。 So simply appending a '+' to any string should do the trick, allowing you to have unique names in a single model and still have the backwards relationships ignored. 因此,只需在任何字符串后添加“ +”即可解决问题,使您可以在单个模型中拥有唯一的名称,而仍然忽略向后关系。
you could always set your own query to the database directly. 您总是可以直接将自己的查询设置到数据库。 I believe the queryset does in fact think the indicator are the same. 我相信queryset实际上确实认为指标是相同的。 I am not sure how friends and enemies interact, but perhaps you can just query there specific id's instead. 我不确定朋友和敌人如何互动,但是也许您可以查询那里的特定ID。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.