【问题标题】:How do I pass a context variable from a view to a custom field/widget in a Django template?如何将上下文变量从视图传递到 Django 模板中的自定义字段/小部件?
【发布时间】:2025-11-23 09:25:01
【问题描述】:

我已经为通过子类化UpdateView 提供服务的表单定义了一个自定义字段和小部件。所以,是这样的:

myapp/forms.py:

from .form_fields import MyCustomField
from .widgets import MyCustomWidget

class MyModelForm(forms.ModelForm):

    my_field = MyCustomField(queryset=MyModel.objects.all(), widget=MyCustomWidget)

myapp/views.py:

from django.views.generic import UpdateView
from .forms import MyModelForm

class MyView(UpdateView):
    form_class = MyModelForm

myapp/widgets.py:

from django.forms import Widget
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe

class MyCustomWidget(Widget):
    context_data = { 'custom_data': custom_data }
    html_output = render_to_string('myapp/widgets/my_custom_widget.html', context_data)
    return mark_safe(html_output)

基本上,我希望能够将custom_data 从我的视图(例如,从会话存储或表单实例)传递到小部件。

【问题讨论】:

    标签: django django-forms django-views django-widget


    【解决方案1】:

    我想通了;我不完全确定这是否是最好的/推荐的方法,但它确实有效。

    首先,在视图中,使用自定义数据更新 get_form_kwargs()。例如,在我的情况下,我想使用附加到表单的实例中的额外数据。

    # myapp/views.py
    from .forms import MyModelForm
    
    
    class MyView(UpdateView):
    
        form_class = MyModelForm
    
        def get_form_kwargs(self):
            kwargs = super(MyView, self).get_form_kwargs()
            form_instance = kwargs.get('instance')
            extra_widget_data = form_instance.widget_data
            kwargs.update({ 'extra_widget_data': extra_widget_data })
            return kwargs
    

    接下来,在表单的 __init__() 中,弹出 kwarg 并将其附加到字段上的自定义小部件:

    # myapp/forms.py
    from django import forms
    
    from .widgets import MyCustomWidget
    
    
    class MyModelForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            extra_widget_data = kwargs.pop('extra_widget_data')
            super(MyModelForm, self).__init__(*args, **kwargs)
            self.fields['my_custom_field'] = MyCustomField(
                widget=MyCustomWidget(extra_widget_data=extra_widget_data)
            )
    

    最后,在您的自定义小部件类中,获取__init__() 中的变量:

    # myapp/widgets.py
    from django.forms import Widget
    from django.template.loader import render_to_string
    from django.utils.safestring import mark_safe
    
    
    class MyCustomWidget(Widget):
    
        def __init__(self, attrs=None, extra_widget_data=None):
            super(MyCustomWidget, self).__init__()
            self.extra_widget_data = extra_widget_data
    
        def render(self, name, value, attrs=None):
            context_data = { 'custom_data': self.extra_widget_data }
            html_output = render_to_string('myapp/widgets/my_custom_widget.html', context_data)
            return mark_safe(html_output)
    

    现在{{ custom_data }} 模板变量可以在来自myapp/widgets/my_custom_widget.html 的渲染HTML 中使用。

    【讨论】:

      【解决方案2】:

      我正在研究一个类似的问题,我想我找到了一种更可靠和更通用的方法来解决这个问题。

      在您的解决方案中,您覆盖 render() 以将其他上下文数据替换为您的小部件。

      但是,当我在 Django 源代码中探索这个概念时,我发现 Django 框架开发人员实际上以一种我认为更好的做法来处理这个确切的问题。

      它们不是覆盖 render(),而是覆盖 get_context(),如 https://docs.djangoproject.com/en/1.11/_modules/django/forms/widgets/ 的 ChoiceWidget 类中所示

      这种方法使您不必担心重新指定渲染代码和模板标识,这可能最好留给专业人士。

      【讨论】:

      • 但是如何将contextrequest 值传递给小部件的get_context?例如,我有 context[obj] 以及如何在 get_context(..) 中访问它
      【解决方案3】:

      你也可以覆盖Widget的get_context方法:

      # myapp/widgets.py
      from django.forms import Widget
      from django.template.loader import render_to_string
      from django.utils.safestring import mark_safe
      
      class MyCustomWidget(Widget):
          template_name = 'myapp/widgets/my_custom_widget.html'
      
          def __init__(self, attrs=None, extra_widget_data=None):
              self.extra_widget_data = extra_widget_data
              super(MyCustomWidget, self).__init__()
      
          def get_context(self, name, value, attrs):
              context = super().get_context(name, value, attrs)
              context['custom_data'] = self.extra_widget_data
              return context
      

      【讨论】:

        最近更新 更多