嵌套和分段脆皮布局

Posted

技术标签:

【中文标题】嵌套和分段脆皮布局【英文标题】:Nested and Segmented Crispy Layouts 【发布时间】:2018-06-30 00:01:26 【问题描述】:

TLDR 问题:如何使用 ¿ 分段制作一个酥脆的表单?(不确定这是否被视为内联)具有多个模型的布局(一些相关,一些不相关)。

我试图理解 Django 中的几件事:表单、表单集、嵌套表单和脆,我已经研究了一段时间,感觉我很接近,只是需要有人帮助连接这些点。我不知道如何在没有脆皮的情况下完成它,所以我开始沿着这条路走,认为脆皮是解决方案。如有错误请指正,谢谢:)

我想要一个表单(如 html 表单,不一定是 Django 表单),它有一个包含很多字段的主要模型,但在主要字段的中间有次要/第三模型。我相当接近布局,但似乎无法让二级/三级模型在布局中间呈现,更不用说在没有脆皮/django 错误的情况下进行编译。

这是我试图达到的颜色编码的视觉效果

我认为我对以下至少一项有误:

我没有调用正确的formfactory 我没有正确使用表单集 我没有在表单助手的布局中正确地将表单字段引用到正确的模型字段 布局不可行,或者我应用了错误的代码结构来获得结果。 我认为我不能直接在下面直接调用两个表单,因为它们不会嵌套/集成

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

#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>

参考文件

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。我不知道类似 DJango 的 Fiddle 环境...

【问题讨论】:

【参考方案1】:

Crispy 与此问题无关。表单可以包含在模板中:

form1
form2
...

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

假设:

我没有调用正确的formfactory 不需要表单工厂,因为任何单个表单都没有多个版本 我没有正确使用表单集 也不需要,因为任何一种形式都没有多个版本 我没有在表单助手的布局中正确地将表单字段引用到正确的模型字段 有点真实 布局是不可能的,或者我应用了错误的代码结构来获得结果。 答案见下文 我认为我不能直接在下面直接调用两个表单,因为它们不会嵌套/集成 一个可以,见下文

使用相关对象/外键制作集成表单的代码:

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,
)

模板.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)

重要部分

在 forms.py 中构建表单时

总体 创建一个父类 (BaseSharedClass),所有需要共享信息的表单都将从该类继承 从父类(class form1Form(BaseSharedClass))扩展所有需要共享信息的表单 关于初始化 从表单中删除共享对象,以避免在同一页面中的所有表单中重复共享字段 (self.currentUser = kwargs.pop('currentUser', None) && self.truck = kwargs.pop('卡车', 无) ) 关于保存 重写保存函数来发挥作用 制作 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] ) 在一行中进行检查

【讨论】:

以上是关于嵌套和分段脆皮布局的主要内容,如果未能解决你的问题,请参考以下文章

使用响应式布局从画布中捕获分段图像

为啥在尝试使用指针访问结构时出现此分段错误?

每天3分钟操作系统修炼秘籍:虚拟内存分段

android TranslateAnimation 顶部segment分段移动动画

如何在 Bootstrap 的单个输入组中进行多个分段输入

ios中带有表格视图的嵌套滚动视图