嵌套和分段的脆皮布局 [英] Nested and Segmented Crispy Layouts

查看:113
本文介绍了嵌套和分段的脆皮布局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TLDR问题:如何使用带有多个模型(有些是相关的,有些不是)的分段(不确定是否认为是内联)布局来制作一个脆皮表单。



我试图了解Django中的几件事:表单,表单集,嵌套表单和酥脆的东西,我花了一段时间了,觉得自己亲密无间,只需要有人帮助连接点。我不确定如何在没有香酥的情况下完成此任务,因此我以这种方式开始了工作,认为香酥是解决方案。如果我错了,请纠正,谢谢:)



我想要一种表单(例如HTML表单,不一定是Django表单),它具有一个主要模型,其中包含许多字段,但在主要字段的中间具有二级/三级模型。我的位置相当接近布局,但似乎无法在布局的中间渲染二级/三级模型,更不用说在编译时不会出现酥脆/ Django错误。



这里是我要达到的颜色的视觉效果



我认为以下至少一项是错误的:




  • 我没有呼叫正确的工厂

  • 我没有正确使用表单集

  • 我没有在表单助手的布局中正确引用表单字段到正确的模型字段

  • 无法进行布局,或者我使用了错误的代码结构来获取结果。

  • 我认为我不能直接调用两种形式直接在下面,因为它们不会嵌套/集成



上面列表项的代码(不能在下面直接放置代码块

 #我认为这不会实现集成/嵌套外观,我的目标是
#views.py:
parent_fo rm = ParentForm()
child_form = ChildForm()
render(template.html,{
pform:parent_form,
cform:child_form
})

#template.html:
< form>
{{pform}}
{{cform}}
< / form>

文件以供参考



models.py



 #图片中的黑色
class Truck(models.Model):
名称= models.CharField (…)


#图片中的蓝色
类QuickInspection(models.Model):
里程表= models.IntegerField(…)
… (created_at,user_cookie#是谁做的……)
卡车=模型。ForeignKey(卡车)

-----
#这两个与卡车中的卡车无关DB,如果至少至少要了解如何完成此操作,我宁愿保持这种状态。
-----
#Red
class Tires(models.Model):
front_tire = models.CharField(…)
…(created_at,…)
truck = models.ForeignKey(Truck)
full_inspection = models.ForeignKey(FullInspection,blank = True,null = True)#可选,如果它具有此外键,那么我知道对Tires进行了全面检查。如果不是,则在快速检查中对它们进行检查,而没有快速检查的外键

#Green
class Brakes(models.Model):
front_axle = models .CharField(...)

createdAt = models.DateTimeField(auto_now_add = True)
truck = models.ForeignKey(Truck)
pm = models.ForeignKey(PM,blank = True,null = True)
full_inspection = models.ForeignKey(FullInspection,blank = True,null = True)#可选,与Tires


views.py



  def weeklyView(request,truckID):
#如果request.method =='POST':POST

#检查表单中的有效数据并保存或提供错误
#返回响应
#GET
否则:
#单独制作每个表格?
quickForm = OHReadingForm(…)
tireForm = TireForm()
akeForm = BrakeForm()

#还是导入表单集和辅助程序?
formset = ExampleFormSet()
helper = ExampleFormSetHelper()

response = render(request,'trucks / weeklyInspection.html',{
'ohrForm':ohrForm ,
'formset':表单集,
'helper':助手,
'tireForm':tireForm,
'truck':卡车,
})



forms.py



  class QuickInspectionForm(forms.ModelForm):
def __init __(self,* args,** kwargs):
super(QuickInspectionForm,self).__ init __(* args,** kwargs)
self.helper = FormHelper()
self.helper.form_tag =假
self.helper.form_method ='post'
self.helper.form_action ='quickInspectionURL'
self.helper.layout = Layout(
Div(
Div(
Fieldset(
''),#'第一个arg是该字段集的图例',
' quickInspectionMetric1',#From QuickInspection.metric1
'quickInspec tionMetric2',#From QuickInspection.metric2
'quickInspectionMetric3',#From QuickInspection.metric3
),
css_class = blue
),
Div(
Fieldset(
'tireMetric1',#from Tire.metric1
'tireMetric2',#from Tire.metric2
css_class = red
),
Div (
Fieldset(
'brakeMetric1',#from Brake.metric1
'brakeMetric2',#from Brake.metric2
css_class = green
),
Div(
Fieldset(
'quickInspectionMetric4',#from QuickInspection.metric4
'quickInspectionMetric5',#from QuickInspection.metric5
css_class = blue
) ,
),
Div(
FormActions(
Reset('reset','Reset'),
Submit( 'submit','Submit')#提交所有

),


类元:
模型= QuickInspection
栏位= [
'metric1','metric2','metric3','metric4','metric5',
'truck',
…,
]

ExampleFormSet = formset_factory(QuickInspectionForm,extra = 1)
#其他失败的尝试
#ExampleFormSet = inlineformset_factory(QuickInspectionForm,extra = 1)
#ExampleFormSet = inlineformset_factory(QuickInspectionForm,TireForm, extra = 1)
#ExampleFormSet = inlineformset_factory(QuickInspectionForm,TireForm,BrakeForm,extra = 1)

class ExampleFormSetHelper(FormHelper):
def __init __(self,* args,* * kwargs):
super(ExampleFormSetHelper,self).__ init __(* args,** kwargs)
self.form_method ='post'
self.form_tag = False
self。 layout = Layout(…)


#与制动形式相同
class TireForm(forms.ModelForm):
def __init __(self,* args,** kwargs):
super(TCForm,self).__ init __(* args,** kwargs)
self.helper = FormHelper()
self.helper.form_method ='post'
self.helper.form_action ='tireURL'
self.helper.layout = Layout(...)
类元:
模型= TireCondition
字段= [
' metric1','metric2',...
'卡车',
]

用于代码回购的JS提琴。我不知道类似DJango的Fiddle环境...

解决方案

脆皮独立于此问题。表单可以包含在模板中,其中之一可以是:

  {{form1}} 
{{form2}}
...

  {%crispy form1 form1.helper%}#尽管此处的帮助程序名称是默认名称,不需要使用。
{%crispy form2%}#form2.helper暗示
。 ..

假设:




  • 我不是在调用正确的工厂


    • 表单工厂不是需要,因为没有任何单个表单的多个版本


  • 我没有正确使用表单集


    • 也不需要,因为任何单一表单都有多个版本


  • 我没有引用该表单字段到正确的模型字段正确在表单助手的布局中


    • 有点像


  • 无法进行布局,或者我应用了错误的代码结构以获得结果。


    • 请参阅以下答案


  • 我不认为我可以直接在下面直接调用两种形式,因为它们不会嵌套/集成


    • 一种可以,见下文




用于创建具有相关对象/外键的集成表格的代码:



views.py:



 如果有request.method =='POST':
formData = request.POST.dict()
form1 = form1Form(formData,instance = currentUser,prefix ='form1')
form2 = form2Form(formData,truck =卡车,user_cookie = currentUser,前缀='form2')
form3 = form3Form(formData,卡车=卡车,实例=卡车,user_cookie = currentUser,前缀='form3')
form4 = form4Form(formData ,truck =卡车,user_cookie = currentUser,前缀='form4')
userForm = userFormForm(formData,truck =卡车,user_cookie = currentUser,前缀='userForm')
...需要其他形式
if all([form1.is_valid( ),form2.is_valid(),form3.is_valid(),form4.is_valid(),userForm.is_valid()]):
currentUser.save()
form1.save()
form2.save()
...
#获取
else:
form1 = form1Form(instance = truck,prefix ='form1')
form2 = form2Form (instance = truck,prefix ='form2')
form3 = form3Form(instance = truck,prefix ='form3')
form4 = form4Form(instance = truck,prefix ='form4')
userForm = userForm(instance = currentUser,前缀='userForm')

return render(request,'trucks / weeklyInspection.html',{
'truck':truck,
'form1':form1,
'form2':form2,
'form3':form3,
'form4':form4,
'userForm':userForm,
})



template.html:



 < div class = container> 
< form action = {%url‘app:formAllView’truck = truck%} class = form method = post>
{{form1}}
{{form2}}
{{form3}}
{{form4}}
#要么将提交手动放入此处的表单或在form4模板
< / form>中



forms.py



 #创建一个共享的
类BaseSharedClass(forms.ModelForm):
def save(self,commit = True):
保存实例,但不保存DB jsut
obj = super(WIBaseClass,self).save(commit = False)
如果提交:
obj.currentUser = self.currentUser
obj。卡车= self.truck
obj.save()
返回obj
def __init __(self,* args,** kwargs):
self.currentUser = kwargs.pop(' currentUser',无)
self.truck = kwargs.pop('truck',无)
super(WIBaseClass,self).__ init __(* args,** kwargs)

#note继承基共享类
class form1Form(BaseSharedClass):
def __init __(self,* args,** kwargs):
super(form1Form,self).__ init __(* args ,** kwargs)

重要部分



在forms.py中构建表单时




  • 总体


    • 使所有需要共享信息的表单都将继承的父类(BaseSharedClass)

    • 扩展所有需要共享信息的表单来自父类(类form1Form(BaseSharedClass))


  • 关于初始化


    • 从表单中删除共享对象,以避免同一页面中所有表单之间共享字段的重复(self.currentUser = kwargs.pop('currentUser',None) && self.truck = kwargs.pop('truck',None))


  • 关于节省


    • 重写保存功能以达到神奇效果

    • make commit = false 以防止它

    • 从传入的上下文中添加相关字段(obj.currentUser = self.currentUser&& obj.truck = self.truck),然后保存(obj。 save())




在视图中创建表单时:




  • 将共享对象 instance = truck 的实例传递给它。如果还需要访问其他对象,也可以传递它们,例如 relatedObject = queriredObject

  • 传递前缀 prefix = formIdentifierN ,因为这有助于Django跟踪哪些独特信息,字段,条目与哪些表单相关联。



不需要特殊的命名,并且form1,form2等...都能很好地工作。在视图中保存表单时:




  • 此处的所有内容与单个表单相同(保存,错误处理等)。 ,但是您可以使用 all([a,b,c,d])

$ b $一行检查它b

TLDR Question: How do you make one crispy form with a ¿segmented?(not sure if this is considered inline) layout with multiple models(some related, some not).

I am trying to understand several things in Django: forms, formsets, nested forms, and crispy, and I've been at it for a while, and feel I am close, just need someone to help connect the dots. I'm not sure how to accomplish it without crispy, so I started down this path thinking crispy was the solution. Please correct if I am wrong, thanks :)

I would like one form (as in HTML form, not necessarily Django Form), that has a primary model with lots of fields, but with secondary/tertiary models in the middle of the primary fields. I am rather close to the layout, but can't seem to get the secondary/tertiary models to render in the middle of the layout, let alone compile without crispy/django erroring.

Here is a color-coded visual of what I am trying to attain

I assume I am wrong with at least one of the following:

  • I am not calling the correct formfactory
  • I am not properly using formsets
  • I am not referencing the form fields to the correct model fields correctly in the layout of the form helper
  • The layout is not possible, or I am applying the wrong code structure to get the result.
  • I don't think I can call two forms directly as directly below, as they would not be nested/integrated

code for above list item (cant put a code block directly below

#I don't think this will achieve the integration/nested look I am aiming for
#views.py:
parent_form = ParentForm()
child_form = ChildForm()
render(template.html, {
  "pform": parent_form,
  "cform": child_form
})

#template.html:
<form>
  {{ pform }}
  {{ cform }}
</form>

Files For reference

models.py

#Black in the picture
class Truck(models.Model):
  name = models.CharField(…)
  …

#Blue in the picture
class QuickInspection(models.Model):
  odometer = models.IntegerField(…)
  … (created_at, user_cookie#who did it, …)
  truck = models.ForeignKey(Truck)

-----
#These two are unrelated to the Truck in the DB, and I would prefer to keep it that way, if for at least to understand how to accomplish this 
-----
#Red
class Tires(models.Model):
  front_tire = models.CharField(…)
  … (created_at, …)
  truck = models.ForeignKey(Truck)
  full_inspection = models.ForeignKey(FullInspection, blank=True, null=True) #optional, and if it has this foreign key, then I know the Tires were looked at in a full inspection.  If not, then they were looked at in the quick inspection, without having a foreign key to the QuickInspection

#Green
class Brakes(models.Model):
  front_axle = models.CharField(…)
  …
  createdAt = models.DateTimeField(auto_now_add=True)
  truck = models.ForeignKey(Truck)
  pm = models.ForeignKey(PM, blank=True, null=True)
  full_inspection = models.ForeignKey(FullInspection, blank=True, null=True) #optional, same as full_inspection in Tires

views.py

def weeklyView(request, truckID):
  # POST
  if request.method == 'POST':
    # Check forms for valid data and save or provide error
    #return response
  # GET
  else:
    #make each form individually?
    quickForm = OHReadingForm(…)
    tireForm = TireForm()
    brakeForm = BrakeForm()

    #Or import a formset and helper?
    formset = ExampleFormSet()
    helper = ExampleFormSetHelper()

    response = render(request, 'trucks/weeklyInspection.html', {
      'ohrForm': ohrForm,
      'formset': formset,
      'helper': helper,
      'tireForm': tireForm,
      'truck': truck,
    })

forms.py

class QuickInspectionForm(forms.ModelForm):
  def __init__(self, *args, **kwargs):
    super(QuickInspectionForm, self).__init__(*args, **kwargs)
    self.helper = FormHelper()
    self.helper.form_tag = False
    self.helper.form_method = 'post'
    self.helper.form_action = 'quickInspectionURL'
    self.helper.layout = Layout(
        Div(
          Div(
            Fieldset(
              '',        # 'first arg is the legend of the fieldset',
              'quickInspectionMetric1', #From QuickInspection.metric1
              'quickInspectionMetric2', #From QuickInspection.metric2
              'quickInspectionMetric3', #From QuickInspection.metric3
            ),            
            css_class="blue"
          ),
          Div(
            Fieldset(
              'tireMetric1',  #from Tire.metric1
              'tireMetric2',  #from Tire.metric2
            css_class="red"
          ),
          Div(
            Fieldset(
              'brakeMetric1',  #from Brake.metric1
              'brakeMetric2',  #from Brake.metric2
            css_class="green"
          ),
          Div(
            Fieldset(
              'quickInspectionMetric4',  #from QuickInspection.metric4
              'quickInspectionMetric5',  #from QuickInspection.metric5
            css_class="blue"
          ),
        ),
        Div(
          FormActions(
            Reset('reset', 'Reset'),
            Submit('submit', 'Submit') #submit for all
          )
        ),
    )

  class Meta:
    model = QuickInspection
    fields = [
      'metric1','metric2','metric3','metric4','metric5',
      'truck',
      …,
    ]

ExampleFormSet = formset_factory(QuickInspectionForm, extra=1)
# Other failed attempts
# ExampleFormSet = inlineformset_factory(QuickInspectionForm, extra=1)
# ExampleFormSet = inlineformset_factory(QuickInspectionForm, TireForm, extra=1)
# ExampleFormSet = inlineformset_factory(QuickInspectionForm, TireForm, BrakeForm, extra=1)

class ExampleFormSetHelper(FormHelper):
  def __init__(self, *args, **kwargs):
    super(ExampleFormSetHelper, self).__init__(*args, **kwargs)
    self.form_method = 'post'
    self.form_tag = False
    self.layout = Layout(…)


#Same as Brake Form
class TireForm(forms.ModelForm):
  def __init__(self, *args, **kwargs):
    super(TCForm, self).__init__(*args, **kwargs)
    self.helper = FormHelper()
    self.helper.form_method = 'post'
    self.helper.form_action = 'tireURL'
    self.helper.layout = Layout(…)
  class Meta:
    model = TireCondition
    fields = [
      'metric1', 'metric2', …
      'truck',
    ]

JS fiddle for code repo. I don't know of a DJango-like Fiddle environment...

解决方案

Crispy is independent of this problem. Forms can be included int the template with either:

{{form1}}
{{form2}}
...

or

{% crispy form1 form1.helper %} #although the helper name here is default and not needed
{% crispy form2 %} # form2.helper is implied
...

For the assumptions:

  • I am not calling the correct formfactory
    • form factory is not needed, as there arent multiple versions of any single form
  • I am not properly using formsets
    • also not needed, as there arent multiple versions of any single form
  • I am not referencing the form fields to the correct model fields correctly in the layout of the form helper
    • somewhat true
  • The layout is not possible, or I am applying the wrong code structure to get the result.
    • see below for answer
  • I don't think I can call two forms directly as directly below, as they would not be nested/integrated
    • one can, see below

Code to make an integrated form with related objects/foreign keys:

views.py:

if request.method == 'POST':
  formData = request.POST.dict()
  form1 = form1Form(formData, instance=currentUser, prefix='form1')
  form2 = form2Form(formData, truck=truck, user_cookie=currentUser, prefix='form2')
  form3 = form3Form(formData, truck=truck, instance=truck, user_cookie=currentUser, prefix='form3')
  form4 = form4Form(formData, truck=truck, user_cookie=currentUser, prefix='form4')
  userForm = userFormForm(formData, truck=truck, user_cookie=currentUser, prefix='userForm')
  ... Other forms as needed
if all([form1.is_valid(), form2.is_valid(), form3.is_valid(), form4.is_valid(), userForm.is_valid()]):
  currentUser.save()
  form1.save()
  form2.save()
  ...
# The Get
else:
  form1 = form1Form(instance=truck, prefix='form1')
  form2 = form2Form(instance=truck, prefix='form2')
  form3 = form3Form(instance=truck, prefix='form3')
  form4 = form4Form(instance=truck, prefix='form4')
  userForm = userForm(instance=currentUser, prefix='userForm')

return render(request, 'trucks/weeklyInspection.html', {
  'truck': truck,
  'form1': form1,
  'form2': form2,
  'form3': form3,
  'form4': form4,
  'userForm': userForm,
})

template.html:

<div class="container">
  <form action="{% url 'app:formAllView' truck=truck %}" class="form" method="post">
    {{ form1 }}
    {{ form2 }}
    {{ form3 }}
    {{ form4 }}
    # Either put the submit in the form here manually or in the form4 template
  </form>

forms.py

# create a shared 
class BaseSharedClass(forms.ModelForm):
  def save(self, commit=True):
  """Save the instance, but not to the DB jsut yet"""
  obj = super(WIBaseClass, self).save(commit=False)
  if commit:
    obj.currentUser = self.currentUser
    obj.truck = self.truck
    obj.save()
  return obj
def __init__(self, *args, **kwargs):
  self.currentUser = kwargs.pop('currentUser', None)
  self.truck = kwargs.pop('truck', None)
  super(WIBaseClass, self).__init__(*args, **kwargs)

#note inherting the base shared class
class form1Form(BaseSharedClass):
  def __init__(self, *args, **kwargs):
    super(form1Form, self).__init__(*args, **kwargs)

THE IMPORTANT PARTS

When Architecting the forms in the forms.py

  • Overall
    • Make a parent class (BaseSharedClass) that all forms that need shared information will inherit from
    • Extend all the forms that need the shared info from the parent class (class form1Form(BaseSharedClass) )
  • With regard to init-ing
    • remove the shared objects from the form, to avoid duplications of the shared fields across all of the forms that will be in the same page (self.currentUser = kwargs.pop('currentUser', None) && self.truck = kwargs.pop('truck', None) )
  • With regard to Saving
    • override the save function to do the magic
    • make commit=false to prevent it from saving just yet
    • add the related fields from the passed in context ( obj.currentUser = self.currentUser && obj.truck = self.truck ), and then save (obj.save() )

When creating the form in the view:

  • pass it the instance of the shared object instance=truck. You can also pass other objects if you need access to them as well, such as relatedObject=queriredObject
  • Pass in the prefix prefix=formIdentifierN, as this helps Django keep track of what unique information, fields, entries are associated with which forms. No special naming is needed, and form1, form2, etc... works well, so long as you know which are each.

When saving the form in the view:

  • everything here is the same (saving, error handling, etc...) as a single form, but you can check it in one line with all( [a,b,c,d] )

这篇关于嵌套和分段的脆皮布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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