django form - 将request.user传递给widget呈现函数

时间:2011-03-10 11:26:21

标签: django django-forms

如何将request.user对象传递到我创建的自定义窗口小部件的渲染函数中,或者从渲染函数中访问当前用户的最佳方法是什么

4 个答案:

答案 0 :(得分:7)

解决方案我认为还不是一个黑客(但接近)并且不是那么大的麻烦。

  1. 覆盖表单上的init:

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super(SomeForm, self).__init__(*args, **kwargs)
        self.fields['your_field'].widget.user = user
    
  2. 覆盖您的小部件:

    def __init__(self, *args, **kwargs):
        self.user = None
        super(YourWidget, self).__init__(*args, **kwargs)
    
  3. 在小部件上为您的用户赚取利润。

  4. 显然你需要向一个表单提供用户,这在一些边缘情况下可能是个问题,例如你使用的是django动态视图而你讨厌将它们更改为更静态的方法。

答案 1 :(得分:3)

根据用户定制小部件并不简单。窗口小部件是表示层中的一个实体,不应该知道请求上下文。您应该自定义表单以获取多个小部件之一或其更改的参数。

创建动态表单是very well documented

答案 2 :(得分:1)

我也遇到过这种情况。有时候只是没有绕过它。请注意,这有点hacky,但它的工作原理。我觉得使用它有点蠢,但这是令人烦恼的交叉问题之一,而且Django人员认为表单字段,窗口小部件或过滤器永远都不能访问请求上下文。< / p>

如果这是somelibrary/templatetags/widgethack.py

from django import template
register = template.Library()

class _WidgetContextWrapper(object):
  def __init__( self, widget=None, context=None ):
    self.widget  = widget
    self.context = context
  def __getattr__( self, attr ):
    return getattr( self.widget, attr )
  def render( self, name, value, attrs=None ):
    try:
      return self.widget.render( name, value, attrs=attrs, context=self.context )
    except TypeError:
      return self.widget.render( name, value, attrs=attrs )

def contextfield( context, field ):
  return field.as_widget( widget=_WidgetContextWrapper( field.field.widget, context ) ) 

register.simple_tag(takes_context=True)(contextfield)

然后您可以通过以下方式在模板中访问它:

{% load widgethack %}
{% contextfield some_field %}

然后你只需要确保你想要的字段有一个覆盖render的小部件来接受额外的context=参数:

from django import forms
from django.template.loader import render_to_string
from django.template.context import Context

class MyWidget( forms.widgets.TextInput ):
  def render( self, name, value, attrs=None, context=None ):
    attrs   = attrs   if attrs   else {}
    context = context if context else Context()
    context.push()
    context["do_what"]="you_want"
    rendered = render_to_string("just_for_example.html",context)
    context.pop()
    return rendered

并使用该小部件:

from django import forms
from wherever import MyWidget

class MyModelForm( forms.ModelForm )
  my_field = forms.CharField( widget=MyWidget )
  ...

唉,我在Django中找到的一个很大的失败是很多类真的需要是类工厂,它们允许你覆盖内部类,比如BoundField,ModelFormOptions和form_factory等返回的类。 :-P </rant>

答案 3 :(得分:1)

这个问题很老,但我遇到了同样的问题,我发现的解决方案似乎很好。下面的小部件只是一个带有一些说明的文本字段:

class TextInputWithInstructions(TextInput):

    def __init__(self, *args, **kwargs):
        self.instruction_text = kwargs['attrs'].pop('instruction_text')
        super(TextInputWithInstructions, self).__init__(*args, **kwargs)

    def render(self, name, value, attrs=None):
        base_output = super(TextInputWithInstructions, self).render(name=name, value=value, attrs=attrs)
        if self.instruction_text is not None:
            base_output = '<p class="form-control-static">' + str(self.instruction_text) + '</p>' + base_output
        return mark_safe(base_output)

然后问题是传递了instruction_text。这是这样解决的:

email_address = MultiEmailFieldString(label=_("Email address"), required=False,
                                      widget=TextInputWithInstructions(
                                          attrs={'instruction_text':
                                                     'Email notifications will be sent to addresses listed below.'}),
                                      help_text=_("Separate multiple addresses with a comma."), )