定制django foreignfield

时间:2017-06-29 23:17:01

标签: django django-models

任何人都知道如何创建一个外键字段,并使它始终指向同一个模型,到目前为止我得到了这些。

class PanMachineTimeUnitField(models.ForeignKey):
    def __init__(self, **kwargs):
        to = 'panbas.PanBasTimeUnit'
        kwargs['verbose_name'] = _('Machine Unit')
        kwargs['related_name'] = 'machine_unit'
        super(PanMachineTimeUnitField, self).__init__(to, **kwargs)

但是我在开始时遇到了错误。 我的目标是使用它,

machine_unit = PanMachineTimeUnitField()

无需进一步声明。

编辑: 我想要这个,因为,我会在几个地方安静地使用这个外键。如果我想更改字段的verbose_name,我希望我的所有字段都受此更改的影响。详细名称就是一个例子,它可能是另一个属性。

我不想使用设置py来声明默认值。

5 个答案:

答案 0 :(得分:7)

我建议您仅使用简单函数来创建一个类似的预先配置的ForeignKey实例:(不是ForeignKey子类的实例)

def pan_machine_time_unit_field(**kwargs):
    othermodel = 'panbas.PanBasTimeUnit'
    on_delete = models.DO_NOTHING  # or what you need
    kwargs['verbose_name'] = 'Machine Unit'
    kwargs.setdefault('related_name', '+')
    # or: kwargs.setdefault('related_name', "%(app_label)s_%(class)s_related",
    return models.ForeignKey(othermodel, on_delete, **kwargs)

class C(models.Model):
    machine_unit = pan_machine_time_unit_field()
    # or:
    # machine_unit = pan_machine_time_unit_field(related_name='klass_c_children')

related_name属性是用于从othermodel的目标对象到引用它的所有对象的向后关系的名称。该名称在其他模型上必须是唯一的(' panbas.PanBasTimeUnit',通常是应用程序和类名称足够独特的名称)或者如果您不想要,该名称可以是'+'创建向后关系查询集。这两个变体都隐含在示例中。还要记住on_delete

如果您确实需要创建子类(如果需要自定义更多方法,这是有意义的),您还必须为迁移定义deconstruct方法。如果您稍后需要修改这样的子类,那将会很复杂。由于migrations on a custom field,它永远不会被删除,重命名等。另一方面,如果您通过函数直接创建一个简单的ForeignKey实例,则可以忽略所有关于迁移的内容。

修改

或者您可以使用该字段创建abstract base model并通过继承或multiple inheritance创建新模型:

class WithPanBasTimeUnit(models.Model):
    machine_unit = models.ForeignKey(
        'panbas.PanBasTimeUnit',
        models.DO_NOTHING,
        verbose_name=_('Machine Unit'),
        related_name='%(app_label)s_%(class)s_related'
    )

    class Meta:
        abstract = True

class ExampleModel(WithPanBasTimeUnit, ...or more possible base models...):
    ... other fields

这个解决方案(灵感来自无效的Ykh)如果您想要将方法添加到具有该字段的模型或将更多字段添加到一起,则非常有用,否则原始解决方案会更容易。

答案 1 :(得分:6)

class PanBasTimeUnit(models.Model):
    machine_unit = models.ForeignKey('self', blank=True, null=True,
                               verbose_name=u'parent')

使用'self''panbas.PanBasTimeUnit'即可。

答案 2 :(得分:4)

对于具有相同related_name的模型,您不能拥有多个外键。

确实,在PanBasTimeUnit实例上,Django在调用<instance>.machine_unit时应该返回哪个管理器?这就是为什么你必须小心related models and abstract classes

如果您删除代码中的kwargs['related_name'] = 'machine_unit',并将其替换为kwargs['related_name'] = "%(app_label)s_%(class)s_related"或类似内容,则该工作正常。

答案 3 :(得分:3)

您的尝试稍作修改即可。

class PanMachineTimeUnitField(models.ForeignKey):
    def __init__(self, **kwargs):
        kwargs["to"] = 'panbas.PanBasTimeUnit'
        kwargs['verbose_name'] = _('Machine Unit')
        kwargs['related_name'] = 'machine_unit'
        super(PanMachineTimeUnitField, self).__init__(**kwargs)

答案 4 :(得分:1)

为什么不直接使用machine_unit = models.ForeignKey(panbas.PanBasTimeUnit, verbose_name=_('Machine Unit'), related_name='machine_unit')) ?