Yun*_*nti 8 django django-models
我在Django中放置了一个圆形外键,这导致名称冲突。我不明白为什么会发生冲突或如何最好地补救。(这是我第一次在模型中使用循环引用-因此我不确定这是否可能是问题的根本原因?)
对于以下内容:
class Supplier(models.Model):
unique_id = models.IntegerField(unique=True)
name = models.CharField(max_length=255, unique=True)
rating = models.FloatField(null=True)
last_updated = models.DateTimeField(auto_now=True)
default_tariff = models.ForeignKey('Tariff')
class Tariff(models.Model):
name = models.CharField(max_length=255)
supplier = models.ForeignKey(Supplier)
end_date = models.DateField(null=True, blank=True)
payment_method = models.ManyToManyField(PaymentMethod)
region = models.ManyToManyField(Region)
Run Code Online (Sandbox Code Playgroud)
错误是:
“ Supplier.default_tariff”的反向查询名称与字段名称“ Tariff.supplier”冲突。提示:重命名字段“ Tariff.supplier”,或在字段“ Supplier.default_tariff”的定义中添加/更改related_name参数。
Goc*_*cht 10
为了避免这种情况,您可以使用related_name:
class Supplier(models.Model):
unique_id = models.IntegerField(unique=True)
name = models.CharField(max_length=255, unique=True)
rating = models.FloatField(null=True)
last_updated = models.DateTimeField(auto_now=True)
default_tariff = models.ForeignKey('Tariff', related_name='+')
class Tariff(models.Model):
name = models.CharField(max_length=255)
supplier = models.ForeignKey(Supplier)
end_date = models.DateField(null=True, blank=True)
payment_method = models.ManyToManyField(PaymentMethod)
region = models.ManyToManyField(Region)
Run Code Online (Sandbox Code Playgroud)
错误消息本身是一个非常正确的语句(您省略了输出中给出的错误代码,我认为它是“E303”),但我们需要了解它的实际含义。
\n我不会问为什么在这种情况下不使用多对多关系,让我们关注“向后”对象关系如何工作:
\n例子:
\nfrom django.db import models\n\nclass Blog(models.Model):\n name = models.CharField(max_length=100)\n def __str__(self):\n return self.name\n\nclass Entry(models.Model):\n blog = models.ForeignKey(Blog, on_delete=models.CASCADE)\n headline = models.CharField(max_length=100)\n def __str__(self):\n return self.headline\nRun Code Online (Sandbox Code Playgroud)\n以下关系 \xe2\x80\x9cbackward\xe2\x80\x9d
\n一对多关系并不以“前向”方式存在,因为它是“多方”,持有密钥,但 Django 为 \xe2\x80\x9cother\xe2\x80\x9d 方创建 API 访问器关系 \xe2\x80\x93 从相关模型到定义该关系的模型的链接。例如,Blog 对象 b 可以通过 entry_set 属性访问所有相关 Entry 对象的列表:b.entry_set.all()。
...
\n如果模型具有外键,则外键模型的实例将有权访问返回第一个模型的所有实例的管理器。默认情况下,该管理器名为 FOO_set,其中 FOO 是源模型名称,小写。该管理器返回查询集,可以按照上面\xe2\x80\x9c检索对象\xe2\x80\x9d部分中的描述对其进行过滤和操作。
\n请点击文档链接获取更多信息/示例。
\n这是因为这些 API 访问器“lated_name”(用抽象类中的 related_name来补充此信息)被实现,以避免字段名和字段名之间的命名冲突。
\n让我们看一下 Django 代码以便更好地理解:
\n这就是你的错误的来源:
\ndef _check_clashes(self):\n """Check accessor and reverse query name clashes."""\n from django.db.models.base import ModelBase\n\n errors = []\n opts = self.model._meta\n\n # `f.remote_field.model` may be a string instead of a model. Skip if model name is\n # not resolved.\n if not isinstance(self.remote_field.model, ModelBase):\n return []\n\n # Consider that we are checking field `Model.foreign` and the models\n # are:\n #\n # class Target(models.Model):\n # model = models.IntegerField()\n # model_set = models.IntegerField()\n #\n # class Model(models.Model):\n # foreign = models.ForeignKey(Target)\n # m2m = models.ManyToManyField(Target)\n\n # rel_opts.object_name == "Target"\n rel_opts = self.remote_field.model._meta\n # If the field doesn\'t install a backward relation on the target model\n # (so `is_hidden` returns True), then there are no clashes to check\n # and we can skip these fields.\n rel_is_hidden = self.remote_field.is_hidden()\n rel_name = self.remote_field.get_accessor_name() # i. e. "model_set"\n rel_query_name = self.related_query_name() # i. e. "model"\n # i.e. "app_label.Model.field".\n field_name = \'%s.%s\' % (opts.label, self.name)\n\n # Check clashes between accessor or reverse query name of `field`\n # and any other field name -- i.e. accessor for Model.foreign is\n # model_set and it clashes with Target.model_set.\n potential_clashes = rel_opts.fields + rel_opts.many_to_many\n for clash_field in potential_clashes:\n # i.e. "app_label.Target.model_set".\n clash_name = \'%s.%s\' % (rel_opts.label, clash_field.name)\n if not rel_is_hidden and clash_field.name == rel_name:\n errors.append(\n checks.Error(\n "Reverse accessor for \'%s\' clashes with field name \'%s\'." % (field_name, clash_name),\n hint=("Rename field \'%s\', or add/change a related_name "\n "argument to the definition for field \'%s\'.") % (clash_name, field_name),\n obj=self,\n id=\'fields.E302\',\n )\n )\n\n if clash_field.name == rel_query_name:\n errors.append(\n checks.Error(\n "Reverse query name for \'%s\' clashes with field name \'%s\'." % (field_name, clash_name),\n hint=("Rename field \'%s\', or add/change a related_name "\n "argument to the definition for field \'%s\'.") % (clash_name, field_name),\n obj=self,\n id=\'fields.E303\',\n )\n )\n\n # Check clashes between accessors/reverse query names of `field` and\n # any other field accessor -- i. e. Model.foreign accessor clashes with\n # Model.m2m accessor.\n potential_clashes = (r for r in rel_opts.related_objects if r.field is not self)\n for clash_field in potential_clashes:\n # i.e. "app_label.Model.m2m".\n clash_name = \'%s.%s\' % (\n clash_field.related_model._meta.label,\n clash_field.field.name,\n )\n if not rel_is_hidden and clash_field.get_accessor_name() == rel_name:\n errors.append(\n checks.Error(\n "Reverse accessor for \'%s\' clashes with reverse accessor for \'%s\'." % (field_name, clash_name),\n hint=("Add or change a related_name argument "\n "to the definition for \'%s\' or \'%s\'.") % (field_name, clash_name),\n obj=self,\n id=\'fields.E304\',\n )\n )\n\n if clash_field.get_accessor_name() == rel_query_name:\n errors.append(\n checks.Error(\n "Reverse query name for \'%s\' clashes with reverse query name for \'%s\'."\n % (field_name, clash_name),\n hint=("Add or change a related_name argument "\n "to the definition for \'%s\' or \'%s\'.") % (field_name, clash_name),\n obj=self,\n id=\'fields.E305\',\n )\n )\n\n return errors\nRun Code Online (Sandbox Code Playgroud)\n这就是 accessor_name 的诞生方式
\ndef get_accessor_name(self, model=None):\n # This method encapsulates the logic that decides what name to give an\n # accessor descriptor that retrieves related many-to-one or\n # many-to-many objects. It uses the lowercased object_name + "_set",\n # but this can be overridden with the "related_name" option. Due to\n # backwards compatibility ModelForms need to be able to provide an\n # alternate model. See BaseInlineFormSet.get_default_prefix().\n opts = model._meta if model else self.related_model._meta\n model = model or self.related_model\n if self.multiple:\n # If this is a symmetrical m2m relation on self, there is no reverse accessor.\n if self.symmetrical and model == self.model:\n return None\n if self.related_name:\n return self.related_name\n return opts.model_name + (\'_set\' if self.multiple else \'\')\nRun Code Online (Sandbox Code Playgroud)\n这是 query_name (也在 related.py 中)
\ndef related_query_name(self):\n """\n Define the name that can be used to identify this related object in a\n table-spanning query.\n """\n return self.remote_field.related_query_name or self.remote_field.related_name or self.opts.model_name\nRun Code Online (Sandbox Code Playgroud)\n现在,您知道了命名是如何完成的以及反向关系是什么,您就会明白为什么
\n\n\n\'Supplier.default_tariff\' 的反向查询名称与字段名称 \'Tariff.supplier\' 冲突。
\n
以及如何解决:
\n\n\n提示:重命名字段“Tariff.supplier”,或添加/更改字段“Supplier.default_tariff”定义中的 related_name 参数。
\n
希望有帮助。我刚刚正在研究相关问题))
\n| 归档时间: |
|
| 查看次数: |
6084 次 |
| 最近记录: |