You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django的values()方法中获取模型的@property自定义属性值?

解决Django中@property字段无法在values()中使用的问题

嘿,我懂你碰到的问题了——你定义了created_date这个@property来格式化created_at日期,但直接在values()里调用它就报错。这是因为values()是直接和数据库交互的,它只能查询数据库里实际存在的字段,而created_date是Python层面生成的属性,数据库根本没有这个字段,所以Django找不到它。

下面给你几种可行的解决方案,你可以根据自己的需求挑:


方案一:在数据库层面用annotate格式化日期(推荐)

这种方法让数据库直接帮我们格式化日期,效率更高,还能和values()完美配合。不过得根据你用的数据库类型调整代码:

如果你用PostgreSQL

PostgreSQL支持TO_CHAR函数来格式化日期,我们可以用Django的Func来调用它:

from django.db.models import Func, Value, models

# 在views.py中
data = Subs.objects.annotate(
    created_date=Func(
        'created_at',
        Value('FMMonth DD YYYY'),  # FM用来去掉月份、日期前的冗余空格
        function='TO_CHAR',
        output_field=models.CharField()
    )
).values('somevalues', 'created_date')

如果你用MySQL

MySQL用DATE_FORMAT函数,我们可以自定义一个Func类封装:

from django.db.models import Func, models

class DateFormat(Func):
    function = 'DATE_FORMAT'
    template = "%(function)s(%(expressions)s, '%(format)s')"

# 在views.py中
data = Subs.objects.annotate(
    created_date=DateFormat('created_at', format='%M %d %Y')
).values('somevalues', 'created_date')

方案二:先查基础字段,再在Python层面处理

如果不想依赖数据库函数,或者需要更复杂的格式化逻辑,可以先把created_at和其他需要的字段查出来,再在Python里转换:

# 在views.py中
# 先获取包含created_at的原始数据
raw_data = Subs.objects.values('somevalues', 'created_at')

# 遍历转换created_date
data = []
for item in raw_data:
    formatted_date = None
    if item['created_at']:
        # 如果created_at是datetime对象,直接调用strftime;如果是字符串就先转成datetime
        formatted_date = item['created_at'].strftime('%B %d %Y')
    
    data.append({
        'somevalues': item['somevalues'],
        'created_date': formatted_date
    })

这种方法的好处是不依赖数据库类型,逻辑灵活,但数据量大的时候性能会不如数据库层面处理。


方案三:封装成自定义QuerySet/Manager(优雅之选)

如果你需要频繁用这个功能,可以把格式化逻辑封装到模型的QuerySet里,调用起来更简洁:

# 在models.py中
from django.db import models
from django.db.models import Func, Value

class SubsQuerySet(models.QuerySet):
    def with_created_date(self):
        # 这里根据你的数据库类型选择实现,比如PostgreSQL版本
        return self.annotate(
            created_date=Func(
                'created_at',
                Value('FMMonth DD YYYY'),
                function='TO_CHAR',
                output_field=models.CharField()
            )
        )

class SubsManager(models.Manager):
    def get_queryset(self):
        return SubsQuerySet(self.model, using=self._db)

class Subs(models.Model):
    # ... 你的其他字段
    created_at = models.DateTimeField(auto_now_add=True, db_column="order_date", null=True, blank=True)
    objects = SubsManager()

    @property
    def created_date(self):
        return self.created_at.strftime('%B %d %Y') if self.created_at else None

然后在views.py里调用就超简单:

data = Subs.objects.with_created_date().values('somevalues', 'created_date')

注意点

别忘了你的created_at字段设置了null=True,所以无论用哪种方法,都要处理created_at为空的情况,避免出现AttributeError或者数据库报错。

内容的提问来源于stack exchange,提问作者Luff li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 01:02:41