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

Django类视图中如何设置GET与POST方法共用的属性

问题原因

Django类视图(CBV)的机制是每收到一次HTTP请求就会实例化一个全新的视图对象:GET请求和POST请求是两次完全独立的请求,对应两个互不关联的类实例。你在GET方法里给self.table赋值,只作用于GET请求对应的临时实例,POST请求到来时生成的新实例根本不存在这个属性,自然会抛错。setattr不生效也是同一个原因——你修改的是上一个请求的实例属性,和当前POST请求的实例没有任何关系。

实现方式

方案1:重写dispatch统一加载(单请求内复用首选)

dispatch是CBV的请求分发入口,所有GET/POST等请求方法执行前都会先经过这个方法。在这里统一拉取需要的表数据并挂载到实例属性上,后续不管走get还是post逻辑都能直接访问,且同一个请求内只会查询一次数据库,不会产生重复开销。

from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.views import View

# 装饰器直接加在dispatch上,不用给get、post重复加
@method_decorator(login_required(login_url='login', redirect_field_name=None), name='dispatch')
class MyClass(View):
    def dispatch(self, request, *args, **kwargs):
        # 统一拉取公共数据,整个请求周期内仅执行一次
        con = create_engine('mysql+mysqlconnector://user:password@localhost:8000/schema')
        tabs = get_tables(con)
        self.target_table = tabs['table_That_I_need']
        self.all_tabs = tabs
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        # 直接访问实例属性即可,无需重复查库
        context = {'data': self.all_tabs}
        return render(request, 'markowitz/markowitz.html', context)

    def post(self, request):
        # 直接拿提前加载好的表数据,不会报属性不存在的错误
        form = MarkowitzForm(request.POST, self.target_table)
        if form.is_valid():
            # 业务逻辑
            pass
        return render(request, 'markowitz/results.html')

方案2:缓存公共数据(全局多请求复用首选)

如果需要的表数据是所有用户通用、更新频率极低的基础数据,没必要每次请求都查库,可以配合Django缓存机制存储,第一次查询后存入缓存,后续所有请求直接从缓存读取,性能更高。

from django.core.cache import cache
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.views import View

@method_decorator(login_required(login_url='login', redirect_field_name=None), name='dispatch')
class MyClass(View):
    def _get_target_table(self):
        # 优先读缓存
        table_data = cache.get('target_db_table')
        if not table_data:
            # 缓存失效时再查库,查完写入缓存,超时时间根据数据更新频率设置即可
            con = create_engine('mysql+mysqlconnector://user:password@localhost:8000/schema')
            tabs = get_tables(con)
            table_data = tabs['table_That_I_need']
            cache.set('target_db_table', table_data, timeout=3600)
        return table_data

    def get(self, request):
        target_table = self._get_target_table()
        context = {'data': target_table}
        return render(request, 'markowitz/markowitz.html', context)

    def post(self, request):
        target_table = self._get_target_table()
        form = MarkowitzForm(request.POST, target_table)
        if form.is_valid():
            # 业务逻辑
            pass
        return render(request, 'markowitz/results.html')
优化提示
  • 不建议在视图方法里频繁创建新的数据库连接,优先复用Django ORM或者数据库连接池,能进一步降低性能开销
  • 类视图的方法装饰器统一加在dispatch方法上即可,无需给每个请求方法单独添加,减少重复代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:18:19