简体   繁体   English

多个多对多关系,且“ related_name”为“ +”会导致错误的查询集

[英]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_setu.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. 但是,这并不优雅。

  1. Is this a limitation of Django's "set related_name to '+'" system? 这是Django的“将related_name设置为'+'”系统的限制吗? (I couldn't find that documented anywhere) - ie that you can only use '+' once per distinct object/object pair? (我找不到在任何地方记录的文档)-即每个唯一的对象/对象对只能使用一次“ +”吗?
  2. Is this a Django bug (ie something to report )? 这是Django的错误(例如要报告的错误)吗?
  3. Is there a better way to work around this issue? 是否有更好的方法来解决此问题?

(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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM