使用Django Formset从多个模型生成动态窗体 [英] Using the Django Formset to Generate a Dynamic Form from Multiple Models

查看:87
本文介绍了使用Django Formset从多个模型生成动态窗体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以这里是我的问题:我正在尝试生成一大堆特征,其中一些是要布局的,有些是填充文本,有些要加上用JS旋转器递减。但是,这里是catch,它们都是用户生成的。我所做的是这样的:在某些方面,我邀请用户通过向模型选项添加对象来创建它的特征,他在其中告诉我特征的名称,它的类型(布尔,文本或数字)。



这是我的简化模型:

  class Characteristic(models。模型)
option = models.ForeignKey('Option')

类选项(models.Model):
option_name = models.CharField(max_length = 100)
OPTION_TYPE_CHOICES =(
('B',u'Bolean'),
('T',u'Textual'),
('N',u'Numerical'),

option_type = models.CharField(max_length = 1,choices = OPTION_TYPE_CHOICES)

类布尔值(特征):
value = models.BooleanField()

class Textual(Characteristic):
value = models.CharField(max_length = 100)

class Numerical(Characteristic):
value = models.PositiveIntegerField

到目前为止,很好。



当生成具有所有可能特征的表单时,问题开始。我所做的是这样的:



这是我的观点:

  @login_required 
def AddCharacteristic(request):

numeric_options = Option.objects.filter(option_type ='N')
textual_options = Option.objects.filter(option_type ='T ')
boolean_options = Option.objects.filter(option_type ='B')

NumericalFormset = modelformset_factory(Numerical,extra = len(numeric_options))
TextualFormset = modelformset_factory ,extra = len(textual_options))
BooleanFormset = modelformset_factory(Boolean,extra = len(boolean_options),form = forms.BooleanForm)

如果request.method =='POST':
numeric_formset = NumericalFormset(request.POST,prefix ='numeric')·
textual_formset = TextualFormset(request.POST,prefix ='textual)
boolean_formset = BooleanFormset(request.POST,prefix = 'boolean')
如果numeric_formset.is_valid()和t extual_formset.is_valid()和boolean_formset.is_valid():
numeric_formset.save()
textual_formset.save()
boolean_formset.save()
如果next在请求中。 GET:
return HttpResponseRedirect(request.GET ['next'])
else:
return HttpResponseRedirect('../../ list /')
else:
boolean_formset = BooleanFormset(queryset = Boolean.objects.none(),prefix ='boolean',initial = [{'option':n.id} for boolean_options])
textual_formset = TextualFormset(queryset = textual.objects.none(),prefix ='textual',initial = [{'option':n.id}在textual_options中为n)]
numeric_formset = NumericalFormset(queryset = Numerical.objects.none() prefix ='numeric',initial = [{'option':n.id} for numeric_options])
return render_to_response('features / add.html',{
'numeric_formset':numeric_formse t,
'textual_formset':textual_formset,
'boolean_formset':boolean_formset,
},context_instance = RequestContext(request))

在我看来:

 < form method =post > 

{%csrf_token%}

{{numeric_formset.management_form}}
{numeric_formset%}中的numeric_form的$%
{{numeric_form}}<峰; br>
{%endfor%}

{{boolean_formset.management_form}}
{boolean_form in boolean_formset%}
{{boolean_form}}< br>
{%endfor%}

{{textual_formset.management_form}}
{text for textual_formset%}
{{textual_form}}< br>
{%endfor%}
< button type =submit> Save< / button>
< button type =reset>取消< / button>
< / form>

所以,这是一种工作,但到目前为止的主要问题是:




  • 我无法重写窗口小部件,将特征选项字段从下拉列表转换为标签。

  • 验证工作。如果用户将文本放在数字字段中或其他方式,Django就不会抱怨。

  • 一般的感觉是我完全弄乱了它,并且设计了一些东西。 :)


解决方案

真的好像您正在尝试创建自己的 EAV 。您可能希望使用 django-eav



如果您仍然想要自己的方式,可以使用 EAV动态表单作为参考。



另外还有一篇很好的文章叫做

还有其他存储和检索动态数据的方法(如 django-hstore django-mutant )。我已经写了关于他们的之前


So here is my problem: I'm trying to generate a big form of with a bunch of characteristics, some of them to be ticket it off if they are boolean, some to be filled with text and some to be incremented or decremented with a JS spinner. But, and here is the catch, all of them are user generated. What I did was this: In some point I invite the user to create it's characteristics by adding objects to the model Option, in which he tells me the name of the characteristics and it's type (boolean, textual or numerical).

Here is my simplified model:

  class Characteristic(models.Model):
      option = models.ForeignKey('Option')

  class Option(models.Model):
      option_name = models.CharField(max_length=100)
      OPTION_TYPE_CHOICES = (
          ('B',u'Bolean'),
          ('T',u'Textual'),
          ('N',u'Numerical'),
      )   
      option_type = models.CharField(max_length=1,choices=OPTION_TYPE_CHOICES)

  class Boolean(Characteristic):
      value = models.BooleanField()

  class Textual(Characteristic):
      value = models.CharField(max_length=100)

  class Numerical(Characteristic):
      value = models.PositiveIntegerField()

So far, so good.

The problem starts when generating that form with all the possible characteristics. What I did was this:

Here is my view:

 @login_required
 def AddCharacteristic(request):

     numerical_options = Option.objects.filter(option_type='N')
     textual_options = Option.objects.filter(option_type='T')
     boolean_options = Option.objects.filter(option_type='B')

     NumericalFormset = modelformset_factory(Numerical,extra=len(numerical_options))
     TextualFormset = modelformset_factory(Textual,extra=len(textual_options))
     BooleanFormset = modelformset_factory(Boolean,extra=len(boolean_options),form=forms.BooleanForm)

     if request.method == 'POST':
         numerical_formset = NumericalFormset(request.POST,prefix='numerical')·
         textual_formset = TextualFormset(request.POST,prefix='textual')
         boolean_formset = BooleanFormset(request.POST,prefix='boolean')
         if numerical_formset.is_valid() and textual_formset.is_valid() and boolean_formset.is_valid():
             numerical_formset.save()
             textual_formset.save()
             boolean_formset.save()
         if 'next' in request.GET:
             return HttpResponseRedirect(request.GET['next'])
         else:
             return HttpResponseRedirect('../../list/')
     else:
         boolean_formset = BooleanFormset(queryset=Boolean.objects.none(),prefix='boolean',initial=[{'option':n.id} for n in boolean_options])
         textual_formset = TextualFormset(queryset=Textual.objects.none(),prefix='textual',initial=[{'option':n.id} for n in textual_options])
         numerical_formset = NumericalFormset(queryset=Numerical.objects.none(),prefix='numerical',initial=[{'option':n.id} for n in numerical_options])
     return render_to_response('characteristics/add.html', {
       'numerical_formset': numerical_formset,
       'textual_formset': textual_formset,
       'boolean_formset': boolean_formset,
     },context_instance=RequestContext(request))

And in my view:

 <form  method="post">

     {% csrf_token %}

     {{ numerical_formset.management_form }}
     {% for numerical_form in numerical_formset %}
     {{ numerical_form }}<br>
     {% endfor %}

     {{ boolean_formset.management_form }}
     {% for boolean_form in boolean_formset %}
     {{ boolean_form }}<br>
     {% endfor %}

     {{ textual_formset.management_form }}
     {% for textual_form in textual_formset %}
     {{ textual_form }}<br>
     {% endfor %}
     <button type="submit">Save</button>
     <button type="reset">Cancel</button>
 </form> 

So, it's kind of working, but the main issue so far is:

  • I'm not being able to rewrite the widget, transforming the characteristic option field from a dropdown to a label.
  • Validation to work. If the user put text in the numerical field or the other way around, Django it's not complaining.
  • The general feeling that I mess it up completely and over engineered something. :)

解决方案

It really looks like you are trying to create your own implementation of EAV. You might want to go with django-eav instead.

If you still want to go your own way, you can use EAV dynamic form as a reference.

Also, there is a nice article called "Dynamic form generation" written by Jacob Kaplan-Moss, one of the lead developers of Django (the article was published in 2010, but, as of today, the described solution is still working).

There are also other approaches for storing and retrieving dynamic data (Like django-hstore and django-mutant). I have already written about them before.

这篇关于使用Django Formset从多个模型生成动态窗体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆