PAYATHON 2026

如何在 Django models 中设置和显示 field choices

支付小周

结论

choices 字段保存的是选项元组中的第一个值。更新订单状态时,应使用字符串或预先定义的常量,不能直接写 Payment Successful:

if response_dict.get("RESPCODE") == "01":
    order.status = "Payment Successful"
    order.save(update_fields=["status"])

在模板中:

  • {{ order.status }} 显示数据库中实际保存的值。
  • {{ order.get_status_display }} 显示该选项对应的可读标签,通常更适合展示给用户。

为什么原来的写法无效

下面的代码不是合法的 Python 字符串赋值:

order.status = Payment Successful

Payment Successful 没有引号,而且中间包含空格,Python 不会把它识别为字符串。正确写法是:

order.status = "Payment Successful"

Django 的 choices 通常是一组二元元组:

(value, label)

其中:

  • value 是存入数据库的值。
  • label 是展示给用户的文本。

目前每个选项的 value 和 label 完全相同,所以 order.status 与 order.get_status_display() 的结果看起来没有区别。

直接修正现有代码

模型可以继续这样写:

class Order(models.Model):
    customer = models.ForeignKey(
        Customer,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
    )

    paymentstatus = (
        ("Payment Successful", "Payment Successful"),
        ("Payment Pending", "Payment Pending"),
        ("Payment Failed", "Payment Failed"),
    )

    status = models.CharField(
        max_length=20,
        blank=True,
        null=True,
        choices=paymentstatus,
    )

支付成功后,设置并保存订单状态:

if response_dict.get("RESPCODE") == "01":
    order.status = "Payment Successful"
    order.save(update_fields=["status"])
    print("order successful")

update_fields=["status"] 并非必需,但可以让 Django 只更新 status 字段。也可以直接调用:

order.save()

前提是 order 已经是从数据库中查询到的 Order 实例。

更推荐的模型写法

为了避免在多个地方重复填写状态字符串,可以使用 Django 的 TextChoices:

from django.db import models


class Order(models.Model):
    class PaymentStatus(models.TextChoices):
        SUCCESSFUL = "successful", "Payment Successful"
        PENDING = "pending", "Payment Pending"
        FAILED = "failed", "Payment Failed"

    customer = models.ForeignKey(
        Customer,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
    )

    status = models.CharField(
        max_length=20,
        choices=PaymentStatus.choices,
        default=PaymentStatus.PENDING,
    )

在视图中可以这样更新:

if response_dict.get("RESPCODE") == "01":
    order.status = Order.PaymentStatus.SUCCESSFUL
    order.save(update_fields=["status"])

这种写法把数据库值和页面显示文本分开:

  • 数据库存储:successful
  • 页面显示:Payment Successful

短而稳定的数据库值便于以后修改展示文案,也可以减少拼写错误。

在模板中显示状态

如果只需要显示数据库保存的原始值,可以使用:

{{ order.status }}

如果要显示 choices 中对应的可读标签,应使用 Django 自动提供的 get_<字段名>_display 方法:

{{ order.get_status_display }}

字段名是 status,对应的方法就是:

{{ order.get_status_display }}

使用 TextChoices 示例时,两者分别显示:

{{ order.status }}
{# 输出:successful #}

{{ order.get_status_display }}
{# 输出:Payment Successful #}

模板调用无参数方法时不需要添加括号,不要写成:

{{ order.get_status_display() }}

注意事项

如果订单创建后始终需要支付状态,建议设置默认值,并去掉 null=True 和 blank=True:

status = models.CharField(
    max_length=20,
    choices=PaymentStatus.choices,
    default=PaymentStatus.PENDING,
)

这样可以避免用空字符串和数据库 NULL 表示同一种“没有状态”的情况。修改模型字段后,还需要生成并执行数据库迁移:

python manage.py makemigrations
python manage.py migrate

备注:内容仅供参考。