如何将request.user对象传递到我创建的自定义窗口小部件的渲染函数中,或者从渲染函数中访问当前用户的最佳方法是什么
答案 0 :(得分:7)
解决方案我认为还不是一个黑客(但接近)并且不是那么大的麻烦。
覆盖表单上的init:
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(SomeForm, self).__init__(*args, **kwargs)
self.fields['your_field'].widget.user = user
覆盖您的小部件:
def __init__(self, *args, **kwargs):
self.user = None
super(YourWidget, self).__init__(*args, **kwargs)
在小部件上为您的用户赚取利润。
显然你需要向一个表单提供用户,这在一些边缘情况下可能是个问题,例如你使用的是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."), )