如何在 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
备注:内容仅供参考。
