2013-12-10 48 views
3

我已經爲子類化UpdateView服務的表單定義了一個自定義字段和窗口小部件。所以,這樣的事情:如何將視圖中的上下文變量傳遞給Django模板中的自定義字段/小部件?

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 (例如來自會話存儲或者窗體實例)添加到窗口小部件。

回答

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可用。

1

我正在研究一個類似的問題,我想我發現了一個更可靠和更通用的方法來解決這個問題。

在您的解決方案中,您會覆蓋render()以將附加上下文數據替換爲您的小部件。但是,當我在Django源代碼中探索這個概念時,我發現Django框架開發人員實際上以我認爲更好的做法處理這個確切問題。

而是覆蓋渲染()它們覆蓋GET_CONTEXT(),截至https://docs.djangoproject.com/en/1.11/_modules/django/forms/widgets/

這種方法使得它,這樣你就不必擔心重新指定的渲染代碼和模板在ChoiceWidget類見過鑑定這可能是最好留給專業人士。

相關問題