Django CBV获取URL变量报错:name 'self' is not defined
解决Django CreateView中URL参数获取失败及表单预填充隐藏需求
你碰到的NameError: name 'self' is not defined问题很典型——在类定义的顶层直接用self是行不通的,这时候类还没被实例化,self这个实例对象根本不存在,只有在类的实例方法内部(比如dispatch、get_initial这类方法),才能通过self访问实例属性和URL传入的kwargs。
下面是修正后的完整代码,同时满足从URL获取site_id、预填充并隐藏site_data字段、传递上下文的需求:
from django.views.generic.edit import CreateView from django.contrib.auth.decorators import user_passes_test from django.utils.decorators import method_decorator from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from .models import SiteSubnets, SiteData class AddSubnet(CreateView): model = SiteSubnets template_name = "sites/edit_subnet.html" # 先移除site_data,后续通过代码预填充并隐藏 fields = ['device_data', 'subnet', 'subnet_type', 'circuit', 'vlan_id', 'peer_desc'] @method_decorator(user_passes_test(lambda u: u.has_perm('config.add_subnet'))) def dispatch(self, *args, **kwargs): # 在请求入口提前获取site_id和对应站点对象,保存为实例属性 self.site_id = self.kwargs['site_id'] self.site = get_object_or_404(SiteData, pk=self.site_id) return super().dispatch(*args, **kwargs) def get_initial(self): # 给site_data字段设置预填充值 initial = super().get_initial() initial['site_data'] = self.site return initial def get_form(self, form_class=None): form = super().get_form(form_class) # 将site_data字段转为隐藏组件,用户看不到但会自动提交 form.fields['site_data'].widget = form.fields['site_data'].hidden_widget() return form def get_success_url(self): # 使用实例属性构建跳转URL,避免变量未定义 return reverse_lazy("sites:site_detail_subnets", args=(self.site_id,)) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 把站点数据传递到模板上下文 context['SiteID'] = self.site_id context['SiteName'] = self.site.location context['active_subnets'] = 'class="active"' return context
关键改动说明:
- 把site_id的获取移到
dispatch方法:dispatch是所有请求的入口,在这里提前获取URL参数并保存为实例属性,后续所有方法都能直接复用,避免重复查询。 - 预填充表单字段:通过
get_initial方法给site_data设置初始值,表单渲染时会自动带上这个值。 - 隐藏字段处理:重写
get_form方法,将site_data的组件替换为隐藏类型,确保用户看不到但提交时会自动携带该值。 - 修正变量引用:所有需要用到
site_id和站点对象的地方,都改为调用实例属性self.site_id和self.site,彻底解决变量未定义的问题。
另外,模板里可以直接使用上下文传递的{{ SiteID }}和{{ SiteName }}显示站点信息,site_data字段会自动以隐藏域的形式存在于表单中,无需额外处理。
内容的提问来源于stack exchange,提问作者AlexW
相关产品推荐
相关产品推荐

