【问题标题】:m2m 'through' field in django models throwing this error: 'M2M field' object has no attribute '_m2m_reverse_name_cache'django 模型中的 m2m“通过”字段引发此错误:“M2M 字段”对象没有属性“_m2m_reverse_name_cache”
【发布时间】:2021-05-09 07:33:10
【问题描述】:

大家好,我正在尝试添加一个 m2m through 字段,以便让我的“部门”模型的助手像 department.assistants.all() 一样调用,但是在这样做时,我收到了这个错误 AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'

这是我的模型:

class Department(models.Model):
    id                  = models.BigAutoField(primary_key=True)
    user                = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    assistants          = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Assistants', related_name='dep_assistants', 
                            symmetrical=False)

class Assistants(models.Model):
    id                  = models.BigAutoField(primary_key=True)
    department          = models.ForeignKey(Department, related_name='of_department', on_delete=models.CASCADE)
    assistant           = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='dt_assistant', 
                            verbose_name="Department Assistant", on_delete=models.CASCADE)
    added               = models.DateTimeField(auto_now_add=True)

我对这个概念很陌生。谁能告诉我我在这里做错了什么?

谢谢

【问题讨论】:

  • 我假设来自AssistantsForeignKey 与来自Department 的m2m 发生碰撞。这个 db 结构甚至似乎没有意义。
  • 是的,这似乎是我上面评论中的问题。如果您搜索_m2m_reverse_name_cache,已经有一些问题处理完全相同的情况:stackoverflow.com/questions/50432609/…
  • 你的settings.AUTH_USER_MODEL是什么,你使用的是哪个版本的Django?
  • settings.AUTH_USER_MODEL 是我的自定义用户模型,它使用电子邮件而不是用户名登录。我使用的是 Django 3.1。

标签: python django django-models django-rest-framework django-views


【解决方案1】:

您定义模型的方式使查询看起来太混乱了。试试下面如何定义模型,然后尝试查询。

您没有在多对多字段定义中提及 through_field 属性。查看文档:https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ManyToManyField

class Department(models.Model):
    # i think this is not needed. Also id is a protected keyword in python.
    # id                  = models.BigAutoField(primary_key=True)
    user                = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    assistants          = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Assistants', 
                                                 related_name='departments', through_fields=("department", "assistant"))

# model name should never be prural. It is singluar becuase it is the name of the object.
class Assistant(models.Model):
    # i think this is not needed. Also id is a protected keyword in python.
    # id                  = models.BigAutoField(primary_key=True)
    department          = models.ForeignKey(Department, on_delete=models.CASCADE)
    assistant           = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name="Department Assistant", on_delete=models.CASCADE)
    added               = models.DateTimeField(auto_now_add=True)


# how to query assistants from departments
# you will get objects of User model
qs = department.assistants.all()


# how to query departments from assistants
# you will get objects of Department model
qs = user.departments.all()


# If you want to query the Assistant model

# from department object
qs = department.assistant_set.all()

# from assistant object
qs = user.assistant_set.all()

# in either case you will get the objects of Assistant model
for i in qs:
    print(i.added, i.department, i.assistant)

试试这个,如果你仍然收到错误,请告诉我。

我的建议是将 Assistant 模型上的 assistant 字段命名为 user。这样您就不需要在多对多字段上定义through_field

【讨论】:

  • 感谢您的回复。我会试试这个,让你知道。
  • 使用through_field 有什么缺点吗?
  • 完全没有缺点。但是您的模型的结构方式应该将该字段称为user 而不是assistant,因为模型称为Assistant。一个助手对象有一个用户和部门作为成员更有意义。
  • 好的。非常感谢。
【解决方案2】:

如果一名助理只与一个部门相关 - 这是一对多的关系。 (一个部门有很多助理)代码如下:

class Assistant(models.Model):
    ...
    department = models.ForeignKey(Department)

无需特别提及部门。获取所有助手:

assistants = models.Assistant.objects.filter(department=department)

或者在类Department上创建一个属性:

@property
def assistants(self):
    return models.Assistant.objects.filter(department=self)

如果一个助手涉及多个部门(每个部门有多个助手),是多对多的关系,它们之间应该有额外的类:

class Assignment(models.Model):
    assistant = models.ForeignKey(Assistant)
    department = models.ForeignKey(Department)

class Department(models.Model):
    ...
    assignment= models.ForeignKey(Assignment)

class Assistant(models.Model):
    ...
    assignment = models.ForeignKey(Assignment)

所以这里查询部门助理:

assistants = models.Assistant.objects.filter(
    assignment__in=models.Assignment.objects.filter(
        department=department
    )
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-18
    • 2013-02-05
    • 2022-01-22
    • 1970-01-01
    • 2015-06-03
    • 2020-03-30
    • 2019-08-09
    相关资源
    最近更新 更多