在Django ORM中如何直接获取字段选项对应值而非存储值?
在Django ORM中直接获取字段选项显示值的方法
当然可以!在Django里,针对带choices的字段,有好几种实用的方法能让你直接从QuerySet里拿到对应的显示值,不用自己手动写映射逻辑。我给你整理几个常用的方案,按需选择:
1. 用Django自带的get_<field>_display()方法
这是最基础也最常用的方式——每个定义了choices的字段,Django都会自动给模型实例生成一个get_<field>_display()方法。举个例子:
假设你的模型是这样的:
class Device(models.Model): PORT_CHOICES = [ (1, 'HTTP端口'), (2, 'HTTPS端口'), (3, 'SSH端口'), ] port = models.IntegerField(choices=PORT_CHOICES)
查询后,每个实例都能直接调用这个方法拿到显示值:
devices = Device.objects.all() for device in devices: print(device.get_port_display()) # 输出对应的端口名称,比如"HTTP端口"
不过要注意,这是实例方法,QuerySet本身不会把这个值作为字段包含进去,需要你逐个访问实例的方法。如果想让QuerySet的每个对象都自带这个属性,可以往下看其他方案。
2. 用annotate在数据库层面添加显示值字段
如果你希望在查询数据库的时候就直接把显示值算出来,并存为QuerySet的一个字段,可以用Case和When组合annotate实现:
from django.db.models import Case, When, Value, CharField # 给QuerySet添加port_name字段,直接对应显示值 devices = Device.objects.annotate( port_name=Case( When(port=1, then=Value('HTTP端口')), When(port=2, then=Value('HTTPS端口')), When(port=3, then=Value('SSH端口')), output_field=CharField(), ) ) # 现在直接访问属性即可 for device in devices: print(device.port_name)
这个方法的优势是计算逻辑在数据库层面完成,适合需要批量获取显示值、或者要对显示值进行过滤/排序的场景。
3. 自定义模型属性(@property)
如果你觉得调用方法有点麻烦,可以在模型里定义一个@property,把显示值包装成属性:
class Device(models.Model): PORT_CHOICES = [ (1, 'HTTP端口'), (2, 'HTTPS端口'), (3, 'SSH端口'), ] port = models.IntegerField(choices=PORT_CHOICES) @property def port_name(self): return self.get_port_display()
这样查询后,直接访问device.port_name就能拿到显示值,写法更简洁,和访问普通模型字段一样。不过这个是在Python层面计算的,和调用方法的性能差不多,适合日常业务代码里使用。
4. 用DRF序列化自动转换(如果做API)
如果你是用Django REST Framework写接口,序列化的时候可以直接让字段自动返回显示值:
from rest_framework import serializers class DeviceSerializer(serializers.ModelSerializer): # 方式1:让port字段直接返回显示值 port = serializers.ChoiceField(choices=Device.PORT_CHOICES) # 方式2:单独新增一个字段返回显示值,保留原port字段 port_name = serializers.CharField(source='get_port_display', read_only=True) class Meta: model = Device fields = ['id', 'port', 'port_name']
序列化后的响应里就会包含对应的端口名称,不用额外处理。
内容的提问来源于stack exchange,提问作者LycuiD
相关产品推荐
相关产品推荐

