在Django中干燥唯一对象

时间:2009-09-07 13:31:15

标签: django-models refactoring dry

我想确保一个对象是唯一的,并且当用户试图保存它时(例如通过管理员)抛出错误,如果没有?通过唯一,我的意思是某些对象的属性可能与其他对象的属性保持相同的值,但它们不能与另一个对象的值相同。

如果我没弄错的话,我可以这样做:

class Animal(models.Model):
    common_name = models.CharField(max_length=150)
    latin_name = models.CharField(max_length=150)
    class Meta:
        unique_together = ("common_name", "latin_name")

但是每次我重构模型(例如添加新字段或更改现有字段的名称)时,我还必须编辑分配给 unique_together <的括号中的字段列表。使用一个简单的模型,没关系,但实际上很重要,在重构过程中会变得非常麻烦。

如何避免重复输入 unique_together 括号中的字段名称列表?有没有办法将模型字段列表传递给变量并将该变量分配给 unique_together

1 个答案:

答案 0 :(得分:4)

重构模型是一件相当昂贵的事情:

  • 您需要使用模型更改所有代码,因为字段名称对应于对象属性
  • 您必须手动更改数据库,因为Django无法为您执行此操作(至少我上次使用Django时使用的版本不能)

因此,我认为更新模型元类中唯一字段名称的列表是您应该担心的最少问题。

编辑:如果你真的想要这样做并且你所有领域的所有必须“独一无二”,那么freenode的那个人是对的,你会有编写自定义元类。这是非常复杂和错误的,加上它可能会使您的代码与Django的未来版本不兼容。

Django的ORM“魔法”由通用基类ModelBase的元类django.db.models.base.ModelBaseModel)控制。该类负责将您的类定义与所有字段和元信息一起使用,并在以后构建您将在代码中使用的类。

以下是有关如何实现目标的方法:

  1. 子类ModelBase使用您自己的元类。
  2. 覆盖方法__new__(cls, name, bases, dict)
  3. 检查dict以收集Meta成员(dict["Meta"])以及所有字段成员
  4. 根据您收集的字段名称设置meta.unique_together
  5. 调用超级实现(ModelBase.__new__
  6. 使用魔术成员__metaclass__ = MyMetaclass为所有独特模型使用自定义元类(或派生扩展Model并覆盖元类的抽象基类)