添加自定义Django模型验证

Cer*_*rin 43 python django django-models

我有一个Django模型,具有开始和结束日期范围.我想强制执行验证,以便没有两个记录具有重叠的日期范围.实现这个的最简单方法是什么,这样我就不必重复自己编写这个逻辑了?

例如,我不想重新实现在一个窗体这个逻辑一个ModelForm 管理员形式模型的重写save().

据我所知,Django并不容易全球实施这些类型的标准.

谷歌搜索并不是很有用,因为"模型验证"通常是指验证特定的模型字段,而不是整个模型内容或字段之间的关系.

Cer*_*rin 50

我发现有用的基本模式是将所有自定义验证放入其中clean(),然后从内部简单地调用full_clean()(哪些调用clean()和一些其他方法)save(),例如:

class BaseModel(models.Model):

    def clean(self, *args, **kwargs):
        # add custom validation here
        super(BaseModel, self).clean(*args, **kwargs)

    def save(self, *args, **kwargs):
        self.full_clean()
        super(BaseModel, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这不是默认设置,如解释在这里,因为它具有某种特征的干扰,但这些都不是我的应用程序有问题.

  • 在Python 3中,`super(BaseModel,self)`可以简化为[`super()`](https://docs.python.org/3/library/functions.html#super)。 (3认同)
  • 依赖保存覆盖是危险的[如果您使用批量操作](https://docs.djangoproject.com/en/4.1/topics/db/models/#overriding-model-methods),因为保存永远不会接到电话 (2认同)

sci*_*shi 22

我会覆盖validate_unique模型上的方法.要确保在验证时忽略当前对象,可以使用以下命令:

from django.db.models import Model, DateTimeField
from django.core.validators import NON_FIELD_ERRORS, ValidationError

class MyModel(Model):
    start_date = DateTimeField()
    end_date = DateTimeField()

    def validate_unique(self, *args, **kwargs):
        super(MyModel, self).validate_unique(*args, **kwargs)

        qs = self.__class__._default_manager.filter(
            start_date__lt=self.end_date,
            end_date__gt=self.start_date
        )

        if not self._state.adding and self.pk is not None:
            qs = qs.exclude(pk=self.pk)

        if qs.exists():
            raise ValidationError({
                NON_FIELD_ERRORS: ['overlapping date range',],
            })
Run Code Online (Sandbox Code Playgroud)

ModelForm将通过a自动为您调用full_clean(),您也可以手动使用.

PPR对简单,正确的范围重叠条件进行了很好的讨论.

  • `from django.core.exceptions import ValidationError,NON_FIELD_ERRORS`` raise ValidationError({NON_FIELD_ERRORS :('重叠日期范围',)})` (6认同)
  • 是否有兴趣扩展`validate_unique`而不仅仅是定义`clean`?只是组织代码的问题? (2认同)

alT*_*Tus 11

我认为你应该使用它:https: //docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects

只需在模型中定义clean()方法,如下所示:(来自docs链接的示例)

def clean(self):
    from django.core.exceptions import ValidationError
    # Don't allow draft entries to have a pub_date.
    if self.status == 'draft' and self.pub_date is not None:
        raise ValidationError('Draft entries may not have a publication date.')
    # Set the pub_date for published items if it hasn't been set already.
    if self.status == 'published' and self.pub_date is None:
        self.pub_date = datetime.datetime.now()
Run Code Online (Sandbox Code Playgroud)

  • 并非一切都干净.无论保存在何处,都需要进行验证.破坏的网站页面比损坏数据更可取. (7认同)
  • 这很接近.我还必须覆盖我的模型的save(),并从那里调用clean(). (4认同)
  • @lajarre,复制错误检查代码是一个可怕的想法.你应该总是遵循DRY. (3认同)
  • 无论如何,@ Cerin似乎不是从save中调用clean的好主意。不要半数遵循Django准则。如果您希望在每个`save()`处发生这种情况,那么就不用担心`clean`并将代码放入`save`方法中了。 (2认同)