奇怪:为什么 Django 相关的多对多查找以这种方式工作(但不像在文档中那样)?

Strange: why Django related many-to-many lookup works this way (but not like in docs)?

Django 文档描述了如何查询反向 m2m 字段: https://docs.djangoproject.com/en/1.8/topics/db/queries/#many-to-many-relationships

根据 this answer 我们应该使用 related_name 作为查询中的第一个参数。

但我无法完成这项工作。 (我正在使用 Django 1.8.5)。这是我的示例模型:

class Nlpneutralfeature(models.Model):   
    neutral_feature = models.CharField(u'found word', max_length=255, default='')   

class Userproject(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="project", verbose_name=("owner"))
    monitoring_words = models.ManyToManyField(Nlpneutralfeature, null=True, blank=True, related_name="monitoringwords")        
    name = models.CharField(u'Название проекта', unique=True, max_length=255)

因此,要获取属于 Userproject 的所有 Nlpneutralfeature 行,其中 Userproject.name == '48',我需要执行以下操作:

Nlpneutralfeature.objects.filter(userproject__monitoringwords__name='48')

但这不起作用。我得到的错误是:Cannot resolve keyword *'userproject'* into field.

因此,Django 无法理解 'userproject' 是小写的模型名称 Userproject.

现在,这是有效的:

Nlpneutralfeature.objects.filter(monitoringwords__name='48')

Django 怎么知道 monitoringwordsrelated_name?没有错误对我来说很奇怪,因为 Nlpneutralfeature 模型中没有 monitoringwords 字段!

注意 Django docs 中的措辞:

The name to user for the relation from the related object back to this one. It's also the default value for related_query_name (the name to use for the reverse filter name from the target model).

在您的示例中,"target model" 是 Nlpneutralfeature。当您在 ManyToManyField Userproject.monitoringwords 上设置 related_name = 'monitoringwords' 时,它告诉 Django 使用 related_nameNlpneutralfeature 模型对象 back 引用到相应的 Userproject 模型对象。

相应地,如果你用related_name = 'foo'声明了Userproject.monitoringwords,那么查询属于项目48的所有Nlpneautralfeatures的方式是:Nlpneautralfeature.objects.filter(foo__name='48').

此处的 related_name 使您可以获得与 Nlpneutralfeature 模型相关的 Userproject 模型。 例如:

nf = Nlpneutralfeature.objects.get(neutral_feature="XXX")
# From here you can get all Userprojects related to this nf like this:
userProjects = nf.monitoringwords.all()

如果你没有声明 related_name 那么你必须这样做:

nf = Nlpneutralfeature.objects.get(neutral_feature="XXX")
# From here you can get all Userprojects related to this nf like this:
userProjects = nf.Userproject_set.all()

我认为你通过逆向理解了这个属性..在我看来你应该在这里声明它是这样的:related_name="user_projects"

总而言之,related_name 是当您想从相关模型中获取当前模型(您声明 M2M 关系的地方)时使用的。