使用auto_now对字段的日期时间字段进行模型验证

kun*_*unl 3 django datetime python-3.x django-rest-framework

一般而言,我对django和python还是陌生的,我试图学习rest_framework来创建RESTful API。

所以我有一个这样的模型:

class Listing(models.Model):
    listingid           = models.BigIntegerField(primary_key=True)
    sellerid            = models.IntegerField()
    createdon           = models.DateTimeField(auto_now_add=True, editable=False)
    expirydate          = models.DateTimeField(null=True)
    validationstatus    = models.SmallIntegerField(default=0)
    listingstatus       = models.SmallIntegerField(
        choices=((0, 'Active'),
            (1, 'Hidden'),
            (2, 'Suspended'),
            (4, 'Expired'),
            (5, 'Deleted'),
            ), 
        default=0)
Run Code Online (Sandbox Code Playgroud)

现在我需要验证该expirydate总是比更大createdon日期。

我知道我可以在视图中执行此操作,我想那不是一个好主意,因为现在验证仅存在于视图中。
这样就剩下了序列化器和模型。

我知道我可以重写save方法来像这样检查它:

class MasterListing(models.Model):
    # fields here..

    def save(self, *args, **kwargs):
        if self.expirydate > self.createdon:
            super().save(*args, **kwargs)
        return ValidationError("Expiry date cannot be greater than created date ("++")")
Run Code Online (Sandbox Code Playgroud)

但是我不知道这是否是一个好主意,因为现在我提出了一个程序员可能忘记抓住的错误。我也不确定在运行此方法时是否会填充字段。
我在文档中读到的另一种clean方法是我不太了解的方法。

在使用rest_framework时,有人可以指导我如何处理这种情况吗?
到目前为止,我已经阅读了一些有关验证的内容:

  1. 序列化器验证
    • 现场水平验证
    • 验证者
  2. 模型验证
    • 覆盖clean方法
    • 覆盖save方法
  3. 只需在视图中手动完成

似乎有很多选择,我什至可能只剩下几个,我不清楚如何在哪里使用。如果这对初学者来说有点抱歉,但是我对框架是陌生的,而django似乎与我在PHP中所做的非常不同。欢迎任何建议!

编辑:由于我们只想构建RESTful API,因此我将仅将django用于rest_framework。

Kev*_*own 5

用于调用的Django REST框架Model.clean曾经是推荐放置验证逻辑的地方,该验证逻辑需要在Django表单和DRF序列化程序中使用。从DRF 3.0开始,情况不再如此,并且在验证周期Model.clean中将不再调用它。有了这一更改,现在可以在两个可能的地方放置可在多个字段上使用的自定义验证逻辑。

如果您仅使用Django REST框架进行验证,并且没有其他需要手动验证数据的区域(例如ModelForm或Django admin中的),那么您应该研究Django REST框架的验证框架

class MySerializer(serializers.ModelSerializer):
    # ...

    def validate(self, data):
        # The keys can be missing in partial updates
        if "expirydate" in data and "createdon" in data:
            if data["expirydate"] < data["createdon"]:
                raise serializers.ValidationError({
                    "expirydata": "Expiry date cannot be greater than created date",
                })

        return super(MySerializer, self).validate(data)
Run Code Online (Sandbox Code Playgroud)

如果您需要结合使用Django REST框架和使用模型级验证的Django组件(例如Django admin),则有两个选择。

  1. Model.clean和中都重复您的逻辑,这Serializer.validate违反了DRY原则,并愿意面对未来的问题。
  2. 进行验证,Model.save希望以后不会发生任何奇怪的情况。

但是我不知道这是否是一个好主意,因为现在我提出了一个程序员可能忘记抓住的错误。

我敢说,引发错误比保存的数据可能故意变得无效要好。一旦开始允许无效数据,就必须在用于修复数据的任何地方进行检查。如果您不允许它进入无效状态,则不会遇到该问题。

我也不确定在运行此方法时是否会填充字段。

您应该能够假定,如果要保存一个对象,则已经使用其值填充了字段。