在Django中干燥唯一对象

sam*_*per 5 refactoring dry django-models

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

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

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")
Run Code Online (Sandbox Code Playgroud)

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

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

Fer*_*yer 4

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

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

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

编辑:如果你真的想这样做,并且你的所有字段都必须“唯一”,那么 freenode 的人是对的,你必须编写一个自定义元类。这是相当复杂且容易出错的,而且它可能会使您的代码与 Django 的未来版本不兼容。

Django 的 ORM“魔力”是由通用基类的元类ModelBase( metaclass) 控制的。该类负责获取包含所有字段和元信息的类定义,并构造稍后将在代码中使用的类。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. 使用 magic 成员将自定义元类用于所有独特的模型__metaclass__ = MyMetaclass(或派生扩展Model和重写元类的抽象基类)

  • 感谢您更新您的回复。是的,我认为实现这一点相当麻烦。唔。如果 Django 可以简单地提供指定 **unique\_together = (all)** 或类似的选项,或者如果它可以允许模型对自身执行内省以生成用于传递给元选项的字段列表等,那就太好了。 或两者 :) (2认同)