如何在表单的 clean() 方法中访问请求对象或任何其他变量?
- 2025-02-27 09:07:00
- admin 原创
- 25
问题描述:
我正在尝试 request.user 来获取表单的 clean 方法,但是如何访问请求对象?我可以修改 clean 方法以允许变量输入吗?
解决方案 1:
Ber 的答案是将其存储在线程本地中,这是一个非常糟糕的想法。完全没有理由这样做。
一个更好的方法是重写表单的__init__
方法以接受一个额外的关键字参数request
。这会将请求存储在表单中,它是必需的,您可以从那里使用 clean 方法访问它。
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self.request ...
您认为:
myform = MyForm(request.POST, request=request)
解决方案 2:
值得一提的是,如果您使用的是基于类的视图,而不是基于函数的视图,请在编辑视图中进行覆盖。自定义CreateViewget_form_kwargs
的示例代码:
from braces.views import LoginRequiredMixin
class MyModelCreateView(LoginRequiredMixin, CreateView):
template_name = 'example/create.html'
model = MyModel
form_class = MyModelForm
success_message = "%(my_object)s added to your site."
def get_form_kwargs(self):
kw = super(MyModelCreateView, self).get_form_kwargs()
kw['request'] = self.request # the trick!
return kw
def form_valid(self):
# do something
上述视图代码将request
作为关键字参数之一提供给表单的__init__
构造函数。因此,在您的ModelForm
do 中:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
# important to "pop" added kwarg before call to parent's constructor
self.request = kwargs.pop('request')
super(MyModelForm, self).__init__(*args, **kwargs)
解决方案 3:
更新于 2011 年 10 月 25 日:我现在将其与动态创建的类而不是方法一起使用,因为 Django 1.3 在其他方面会显示一些奇怪之处。
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj, **kwargs)
class ModelFormWithRequest(ModelForm):
def __new__(cls, *args, **kwargs):
kwargs['request'] = request
return ModelForm(*args, **kwargs)
return ModelFormWithRequest
然后MyCustomForm.__init__
按如下方式覆盖:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
ModelForm
然后您可以通过的任何方法访问请求对象self.request
。
解决方案 4:
通常的方法是使用中间件将请求对象存储在线程本地引用中。然后您可以从应用程序中的任何位置访问它,包括 Form.clean() 方法。
更改 Form.clean() 方法的签名意味着您拥有自己的、修改过的 Django 版本,这可能不是您想要的。
感谢中间件计数看起来像这样:
import threading
_thread_locals = threading.local()
def get_current_request():
return getattr(_thread_locals, 'request', None)
class ThreadLocals(object):
"""
Middleware that gets various objects from the
request object and saves them in thread local storage.
"""
def process_request(self, request):
_thread_locals.request = request
按照Django 文档中的说明注册此中间件
解决方案 5:
对于 Django 管理员,在 Django 1.8 中
class MyModelAdmin(admin.ModelAdmin):
...
form = RedirectForm
def get_form(self, request, obj=None, **kwargs):
form = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
form.request = request
return form
解决方案 6:
我在自定义管理员时遇到了这个特殊问题。我希望根据特定管理员的凭据验证某个字段。
由于我不想修改视图以将请求作为参数传递给表单,所以我做了以下事情:
class MyCustomForm(forms.ModelForm):
class Meta:
model = MyModel
def clean(self):
# make use of self.request here
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
def form_wrapper(*args, **kwargs):
a = ModelForm(*args, **kwargs)
a.request = request
return a
return form_wrapper
解决方案 7:
Daniel Roseman的答案仍然是最好的。但是,出于以下几个原因,我会使用请求的第一个位置参数而不是关键字参数:
你不会冒着覆盖同名 kwarg 的风险
请求是可选的,这是不对的。在此上下文中,请求属性不应该为 None。
您可以干净地将 args 和 kwargs 传递给父类,而不必修改它们。
最后,我将使用更独特的名称来避免覆盖现有变量。因此,我修改后的答案如下:
class MyForm(forms.Form):
def __init__(self, request, *args, **kwargs):
self._my_request = request
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self._my_request ...
解决方案 8:
您不能总是使用此方法(这可能是不好的做法),但如果您仅在一个视图中使用表单,则可以将其范围限定在视图方法本身内。
def my_view(request):
class ResetForm(forms.Form):
password = forms.CharField(required=True, widget=forms.PasswordInput())
def clean_password(self):
data = self.cleaned_data['password']
if not request.user.check_password(data):
raise forms.ValidationError("The password entered does not match your account password.")
return data
if request.method == 'POST':
form = ResetForm(request.POST, request.FILES)
if form.is_valid():
return HttpResponseRedirect("/")
else:
form = ResetForm()
return render_to_response(request, "reset.html")
解决方案 9:
来自 cheesebaker@pypi 的新鲜奶酪:django-requestprovider
解决方案 10:
我对这个问题还有另一个答案,根据你的要求,你想通过表单的 clean 方法访问用户。你可以试试这个。View.py
person=User.objects.get(id=person_id)
form=MyForm(request.POST,instance=person)
表单.py
def __init__(self,*arg,**kwargs):
self.instance=kwargs.get('instance',None)
if kwargs['instance'] is not None:
del kwargs['instance']
super(Myform, self).__init__(*args, **kwargs)
现在,您可以通过 form.py 中的任何 clean 方法访问 self.instance
解决方案 11:
当您想通过“准备好的”Django 类视图访问它时,CreateView
有一个小技巧需要了解(= 官方解决方案无法开箱即用)。CreateView
您必须在自己的解决方案中添加如下代码:
class MyCreateView(LoginRequiredMixin, CreateView):
form_class = MyOwnForm
template_name = 'my_sample_create.html'
def get_form_kwargs(self):
result = super().get_form_kwargs()
result['request'] = self.request
return result
= 简而言之,这是request
使用 Django 的创建/更新视图传递给表单的解决方案。
解决方案 12:
摘自https://stackoverflow.com/a/52275325/2351696
在基于类的视图中,您需要覆盖get_form_kwargs
:
class MyView(View):
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs(*args, **kwargs)
kwargs['request'] = self.request
return kwargs
默认情况下, AForm
无权访问该request
对象。因此您需要将其传递给构造函数。
class MyCustomForm(forms.ModelForm):
def __init__(self, *args<b>, request=None</b>, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)