【问题标题】:DRF: Programmatically get default choice from TextChoices fieldDRF:以编程方式从 TextChoices 字段中获取默认选择
【发布时间】:2021-08-14 11:16:17
【问题描述】:

我们的网站是一个 Vue 前端/DRF 后端。在serializer.validate() 方法中,我需要以编程方式确定TextChoices 类中的哪个选项已被指定为模型字段的默认值。

TextChoices 类(简例):

class PaymentMethod(models.TextChoices):
    BANK_TRANSFER = 'Bank Transfer'
    CREDIT_CARD = 'Credit Card'
    PAYPAL = 'PayPal'
    OTHER = 'Other'

型号:

class InvoicePayment(CommonFieldsModelMixin,
                     StatusFieldModelMixin,
                     models.Model):

    ...other fields omitted...
    payment_method = models.TextField(
        verbose_name=_('Method'),
        choices=PaymentMethod.choices,
        default=PaymentMethod.OTHER,
    )
    payment_method_other = models.TextField(
        verbose_name=_('Payment Method Other'),
        default='',
    )

我们的用户能够绕过前端并直接发布到 API,这意味着他们可能会忽略 POST 数据中的字段 - 无论是由于疏忽还是因为字段具有默认值。但是,对于上述模型,仅当 payment_method 为“Other”时才需要 payment_method_other。该检查是在serializer.validate() 方法中完成的。

如果在前端的表单上选择“其他”,则没有问题,因为该值存在于传递给validate() 方法的validated_data 中。但是,如果用户直接向 API 发帖并省略了payment_method,则在执行validate() 方法之后,在数据库级别(或多或少)完成默认值处理。

为了保持 DRY,并避免在将来更改默认值时出现不匹配的代码,我不想在 validate() 方法中硬编码“Other”的默认值。相反,我想访问字段定义信息(元数据?)并以编程方式确定模型上定义的默认值。

【问题讨论】:

  • 我添加了一个关于确定字段默认值的方法的答案。但是根据我对您对序列化程序的解释的了解,您无法处理省略payment_method 的情况?仍然可以通过检查该字段是否存在来在验证中进行检查?
  • @bdbd,正确。如果我在validated_data 中找不到payment_metod,我知道我需要提供与 将提供 相同的默认值,因为它是在模型上定义的(我现在可以通过您的答案中非常简单的解决方案;谢谢)。然后,如果它恰好是“其他”,它将通过/失败验证,就像用户输入它一样。
  • 好的,现在很清楚了。我只是在想,当它被省略时,你可以像Other一样进行默认处理,就像payment_method一样,你不需要明确设置它,因为db会为你做。

标签: python django django-models django-rest-framework


【解决方案1】:

一种无需过多修改的方法是将默认值定义为模型的属性,如下所示:

class InvoicePayment(CommonFieldsModelMixin,
                     StatusFieldModelMixin,
                     models.Model):

    DEFAULT_PAYMENT_METHOD = PaymentMethod.OTHER

    ...other fields omitted...
    payment_method = models.TextField(
        verbose_name=_('Method'),
        choices=PaymentMethod.choices,
        default=DEFAULT_PAYMENT_METHOD,
    )
    payment_method_other = models.TextField(
        verbose_name=_('Payment Method Other'),
        default='',
    )

然后你可以通过模型轻松访问默认值:

InvoicePayment.DEFAULT_PAYMENT_METHOD

【讨论】:

    猜你喜欢
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多