Вложенные и сегментированные хрустящие макеты

Вопрос TLDR: Как создать одну хрустящую форму с сегментированным (не уверен, если это считается встроенным) макетом с несколькими моделями (некоторые связаны, некоторые нет).

Я пытаюсь понять несколько вещей в Django: формы, наборы форм, вложенные формы и хрустящие, и я был на нем некоторое время, и чувствую, что я рядом, просто нужен кто-то, чтобы помочь соединить точки. Я не уверен, как сделать это без хрустящих, поэтому я пошел по этому пути, думая, что хрустящий был решением. Пожалуйста, исправьте, если я ошибаюсь, спасибо:)

Я хотел бы одну форму (как в форме HTML, не обязательно форма Джанго), которая имеет первичную модель с большим количеством полей, но с вторичными / третичными моделями в середине первичных полей. Я довольно близок к макету, но не могу заставить вторичные / третичные модели визуализироваться в середине макета, не говоря уже о компиляции без хрустящих ошибок / ошибок django.

Вот цветное изображение того, чего я пытаюсь достичь Интегрированные модели в хрустящей форме

Я предполагаю, что ошибаюсь хотя бы с одним из следующих:

  • Я не называю правильной формфакторией
  • Я не правильно использую формы
  • Я не ссылаюсь на поля формы на правильные поля модели в макете помощника формы
  • Компоновка невозможна, или я применяю неправильную структуру кода, чтобы получить результат.
  • Я не думаю, что могу вызвать две формы напрямую, как указано ниже, так как они не будут вложенными / интегрированными

код для указанного выше элемента списка (нельзя поместить кодовый блок непосредственно под

#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 скрипка для репо кода. Я не знаю, как DJango-подобная среда Fiddle...

1 ответ

Решение

Хрустящий не зависит от этой проблемы. Формы могут быть включены в шаблон с помощью:

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

или же

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

Для предположений:

  • Я не называю правильной формфакторией
    • Фабрика форм не нужна, так как не существует нескольких версий какой-либо одной формы
  • Я не правильно использую формы
    • также не требуется, так как не существует нескольких версий какой-либо одной формы
  • Я не ссылаюсь на поля формы на правильные поля модели в макете помощника формы
    • несколько верно
  • Компоновка невозможна, или я применяю неправильную структуру кода, чтобы получить результат.
    • см. ниже для ответа
  • Я не думаю, что могу вызвать две формы напрямую, как указано ниже, так как они не будут вложенными / интегрированными
    • можно, см. ниже

Код для создания интегрированной формы со связанными объектами / внешними ключами:

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)

ВАЖНЫЕ ЧАСТИ

При проектировании форм в forms.py

  • В общем и целом
    • Создайте родительский класс (BaseSharedClass), от которого будут наследоваться все формы, которым требуется общая информация.
    • Расширьте все формы, которые нуждаются в общей информации из родительского класса (класс 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] )
Другие вопросы по тегам