如何在表单的 clean() 方法中访问请求对象或任何其他变量?

2025-02-27 09:07:00
admin
原创
26
摘要:问题描述:我正在尝试 request.user 来获取表单的 clean 方法,但是如何访问请求对象?我可以修改 clean 方法以允许变量输入吗?解决方案 1:Ber 的答案是将其存储在线程本地中,这是一个非常糟糕的想法。完全没有理由这样做。一个更好的方法是重写表单的__init__方法以接受一个额外的关键...

问题描述:

我正在尝试 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__构造函数。因此,在您的ModelFormdo 中:

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的答案仍然是最好的。但是,出于以下几个原因,我会使用请求的第一个位置参数而不是关键字参数:

  1. 你不会冒着覆盖同名 kwarg 的风险

  2. 请求是可选的,这是不对的。在此上下文中,请求属性不应该为 None。

  3. 您可以干净地将 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
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1298  
  华为IPD产品开发流程是一套先进且成熟的产品开发管理体系,对众多企业提升产品竞争力有着重要的借鉴意义。它涵盖多个关键要素,这些要素相互关联、相互作用,共同构建起高效、科学的产品开发流程。深入剖析其中的五个核心要素,能让我们更好地理解华为成功背后的产品开发逻辑,为企业的产品创新与发展提供有力的指导。市场管理市场管理是IP...
IPD框架   13  
  华为集成产品开发(IPD)体系作为一套先进的产品开发管理理念和方法,在华为的发展历程中发挥了至关重要的作用。在供应链管理领域,IPD同样展现出巨大的价值,深刻影响着企业的运营效率、产品质量以及市场竞争力。通过将IPD理念融入供应链管理,华为实现了从产品规划到交付的全流程优化,为企业的持续发展奠定了坚实基础。IPD对供应...
IPD集成产品开发流程   15  
  IPD(Integrated Product Development)项目管理作为一种先进的产品开发管理模式,旨在通过整合跨部门资源,实现产品的高效开发与上市。然而,在实际推行过程中,IPD项目管理面临着诸多风险,若处理不当,可能导致项目进度延迟、成本超支甚至项目失败。深入了解这些风险并制定有效的应对策略,对于保障IP...
华为IPD流程   14  
  华为作为全球知名的科技企业,其成功背后的管理模式备受关注。其中,IPD(集成产品开发)产品开发流程对华为的创新发展起到了至关重要的推动作用。IPD不仅仅是一种流程,更是一种先进的管理理念,它将产品开发视为一个系统工程,涵盖了从市场需求分析、产品规划、研发、生产到上市等多个环节,通过整合企业内外部资源,实现高效、协同的产...
IPD流程中PDCP是什么意思   14  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用