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

Django4 QuerySet不返回最新数据 需重启服务如何解决

问题描述

更新房产(House)属性时出现异常:将State字段修改为Illinois后,更新值无法在如下查询结果中正常展示:

all_properties = models.Property.objects.all()

即便新增房产记录,重载UpdateView后all_properties的查询结果依然不包含新数据,只有终止并重启Django服务才能查询到最新写入的数据。需要找到配置方法让UpdateView每次加载时都展示最新数据。

业务背景

定义的房产模型包含20余个属性,用于搭建类Airbnb的房产listing站点,模型字段覆盖面积、卧室数、城市、州等信息。
编辑房产属性时需要为文本输入框实现自动补全功能:例如表单中State是文本字段,新增第二套房产时,State输入框需要基于系统中已存的房产数据给出补全建议——输入C时,若数据库中存在State为California的房产,就需要展示该选项。

现有实现代码

使用UpdateView实现房产编辑页,需要将所有自动补全字段数据传入视图,供前端文本框调用,视图代码如下:

class PropertyUpdateView(LoginRequiredMixin, UpdateView):
    context_object_name = 'property'
    model = models.Property
    form_class = forms.PropertyForm
    template_name = 'desertland/admin/property_update.html'

    extra_context = get_autocomplete_fields()

    def get_success_url(self):
        messages.success(self.request, 'The property was updated successfully.')
        return reverse('property_update', kwargs={'pk': self.object.id})

自动补全数据通过extra_context传入,对应的get_autocomplete_fields()方法实现如下:

def get_autocomplete_fields():
    ac_keys = ['state', 'city', 'county', 'zip_code', 'zoning', 'power', 'water_district', 'water', 'access', 'vetting']
    autocomplete_data = {}
    temp_list = {}

    all_properties = models.Property.objects.all()

    # 为自动补全字段初始化空字典
    for key in ac_keys:
        temp_list[key] = []
        autocomplete_data[key] = []

    for property in all_properties:
        for key in ac_keys:
            # 不存在对应key时初始化
            if autocomplete_data.get(key) is None:
                autocomplete_data[key] = []

            val = getattr(property, key)

            # 从房产数据中提取去重后的值生成数组
            if val and val not in temp_list[key]:
                temp_list[key].append(val)
                autocomplete_data[key].append({'value': val, 'label': val})

    return {'autocomplete_data': autocomplete_data}

该函数逻辑正常,可正确生成符合要求的字典数据。

数据库模型定义如下:

class Property(models.Model):
    id = models.AutoField(primary_key=True)
    slug = models.SlugField(unique=True, db_index=True)
    name = models.TextField(null=False, blank=False)
    ... 其余属性 ...

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super(Property, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse("property_update", kwargs={'id': self.pk})

发布问题前已完成的排查项:

  • 数据更新后会立即写入数据库
  • 通过ListView或UpdateView访问单条对象时,可正常展示更新后的值(输入框、数据列表中均可正常显示)
  • 只有通过models.Property.objects.all()查询的结果,需要重启Django服务才会同步最新数据
  • 新建对象后,models.Property.objects.all()返回的结果计数保持不变,即便新对象已持久化到数据库也无法被查询到
  • 项目未启用任何缓存框架
  • 在settings.py中设置TIMEOUT=0未产生任何效果
问题根因

问题出在extra_context的赋值方式:把extra_context定义为类属性时,get_autocomplete_fields()会在Django服务启动、类加载时执行一次,查询结果直接固化在类属性里,后续所有请求复用的都是服务启动时生成的这份静态数据,根本不会重新查询数据库,自然拿不到更新、新增的内容,只有重启服务重新加载类才会重新执行查询。

修复方案

删除类层面的extra_context = get_autocomplete_fields()赋值,重写类视图的get_context_data方法,在每次处理请求时实时查询最新的自动补全数据,修改后的视图代码如下:

class PropertyUpdateView(LoginRequiredMixin, UpdateView):
    context_object_name = 'property'
    model = models.Property
    form_class = forms.PropertyForm
    template_name = 'desertland/admin/property_update.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update(get_autocomplete_fields())
        return context

    def get_success_url(self):
        messages.success(self.request, 'The property was updated successfully.')
        return reverse('property_update', kwargs={'pk': self.object.id})
额外优化建议

当前get_autocomplete_fields的实现会把全量房产数据加载到内存中遍历去重,当房产数据量增大后性能会明显下降,可以直接用数据库层面的去重查询替代内存遍历,不需要把所有房产对象捞到内存里循环处理,示例逻辑如下:

def get_autocomplete_fields():
    ac_keys = ['state', 'city', 'county', 'zip_code', 'zoning', 'power', 'water_district', 'water', 'access', 'vetting']
    autocomplete_data = {}
    for key in ac_keys:
        # 直接在数据库层做去重、空值过滤
        distinct_vals = models.Property.objects.exclude(**{f"{key}__isnull": True})
                                            .exclude(**{key: ""})
                                            .values_list(key, flat=True)
                                            .distinct()
        autocomplete_data[key] = [{"value": val, "label": val} for val in distinct_vals]
    return {'autocomplete_data': autocomplete_data}

修改后查询效率会有明显提升。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:36:13