【问题标题】:Django 1.9: Field clashes with the field of non-existing field in parent modelDjango 1.9:字段与父模型中不存在的字段的字段冲突
【发布时间】:2016-03-09 06:58:46
【问题描述】:

我有一些简单的模型,Profile、Certifier 和 Designer,后者继承自 Profile(多表继承)。在 Designer 中,有一个 Certifier 的外键。

class Profile(models.Model):
    TYPES = (
        ('admin', _('Administrator')),
        ('certifier', _('Certifier')),
        ('designer', _('Designer'))
    )
    
    user = models.OneToOneField(User)
    type = models.CharField(max_length=9, choices=TYPES)
    
    def __str__(self):
        return self.user.username + ' (' + self.type + ')'

class Admin(Profile):
    pass
class Certifier(Profile):
    pass
class Designer(Profile):
    certifier = models.ForeignKey(Certifier)

在 Django 1.8 中这可以完美运行,但在 1.9 中我得到了;

django.core.management.base.SystemCheckError: SystemCheckError: 系统检查发现一些问题:

错误:

check.Designer.certifier:(models.E006)字段“certifier”与模型“check.profile”中的字段“certifier”冲突。

(在这种情况下,Profile.type 无关紧要,我只需要它来区分登录的用户配置文件类型)。

check.profile 显然没有“验证者”字段。这是一个错误还是我错过了什么?同样的事情发生在另一个项目中。

【问题讨论】:

  • 您是否有冲突的迁移文件(可能是 006)?您是否共享数据库?你提到它发生在另一个项目中
  • @Sayse E006 是系统检查框架中的 error code,而不是迁移编号。
  • @Alasdair - 啊当然是,仍然认为问题是(曾经)可能是冲突迁移
  • 1.8 没有迁移问题,也没有和其他程序共享数据库。重命名字段后,由 admin 和 auth 中的 1.9 升级引起的迁移也运行良好。这个问题的另一个发生是在另一个项目中,但也有一个带有外键的多表继承的情况:父模型组件,Window和Spacer都继承自Component,并且有一个从Window指向Spacer的外键,并且字段名称是 spacer。
  • 这似乎是 1.9 中的糟糕设计,或者只是一个错误。我现在有一个在 1.8 下创建的功能完善的数据库,它在 1.9 中的 makemigrations 上出错。另外,related_name 似乎是解决问题的明显解决方案,但事实并非如此。

标签: django name-clash multi-table-inheritance django-1.9


【解决方案1】:

我认为您不应该为该外键关系使用名称验证器,因为根据docs,类 Profile 实际上具有 certifieradmindesigner 字段(尽管通过描述符),在这种情况下名称实际上会发生冲突。

from django.contrib.auth.models import User

c = Certifier.objects.create(
    type='admin',
    user=User.objects.latest('date_joined'),
)

p = c.profile_ptr
print(p.certifier) #username (admin)

改成certifier_field = models.ForeignKey(Certifier)之类的东西

正如 cmets 中指出的,您可以将模型重命名为 CertifierProfile、AdminProfile 等以避免冲突。

或者您也可以通过将SILENCED_SYSTEM_CHECKS = ['models.E006'] 添加到您的settingssilence the check,但这不是一个好方法。

【讨论】:

  • 它解决了 1.9 中的问题,但是,拥有这样的字段名并不好,尤其是因为在 1.8 之前,使用字段名验证器一切正常。
  • Django docs 表示您可以使用 profile.certifier 从父模型 Profile 转到其子模型 Certifier。定义另一个 certifier 字段是不明确的,因此在 1.9 中添加了对此的检查。如果你真的想这样做,你可以通过在你的设置中添加SILENCED_SYSTEM_CHECKS = ['models.E006']silence the check,但我不建议这样做。
  • 如果您不喜欢certifier_field,可以将模型重命名为CertifierProfileAdminProfile 等以避免冲突。或者,您可以尝试将parent field 设置为related_name
  • 好的,感谢您的解决方案、解释和 cmets!
  • 就我而言(使用 django_model_utils InheritanceManager),使检查静音似乎是最好的解决方案。将不合理的名称应用于字段作为一种变通方法并不吸引人。一切似乎都很好,包括超类和子类上的属性名称(不是我需要前者)。
【解决方案2】:

您可以指定Profileabstract class。这将防止检查与您的父字段混淆。

class Meta:
    abstract = True

【讨论】:

  • 我认为“永远不要让字段名称与模型名称匹配”可能是一个很好的经验法则,但是如果您有大量与该字段相关的逻辑,这样做可以帮助避免重大重写名称(即该字段存在于 API 端点上,并被消费应用所依赖)
  • 谢谢,这行得通,我不需要重命名任何东西。
猜你喜欢
  • 2021-10-19
  • 2022-10-24
  • 2021-11-29
  • 1970-01-01
  • 2013-11-09
  • 2016-05-31
  • 2017-10-02
  • 2013-02-03
  • 1970-01-01
相关资源
最近更新 更多