2013-03-01 11 views
11

Ich habe einen Django Formset, den ich in der Mitte eines anderen Formulars erstellen möchte. Ich verwende django-crispy-forms__init__ ist das Layout in dem übergeordneten Formular zu setzen:django knusprige Formen: Verschachteln eines Formsets in einem Formular

from crispy_forms.helper import FormHelper 
from crispy_forms.layout import Submit, Layout, Field, Div 
def __init__(self, *args, **kwargs): 
    self.helper = FormHelper() 
    self.helper.layout = Layout(
     Div(
      Div(Field('foo'), css_class='span3'), 
      Div(Field('bar'), css_class='span4'), 
      css_class='row' 
      ), 
     Field('baz', css_class='span1'), 
      ... 
      ) 
    self.helper.add_input(Submit('submit', 'Submit', css_class='btn btn-primary offset4')) 

Meine Vorlage einfach macht das Formular mit dem {% crispy %}-Tag.

Ich würde gerne wissen, wie ich das Formset integrieren sollte. Sollte ich es in der obigen Init-Funktion instanziieren? Wie beziehe ich mich darauf?

Es gibt other examples von Form- und Formset-Combos online, die einen Render nach dem anderen seriell haben, aber ich frage mich, ob ich mehr Kontrolle darüber haben kann, wie sie mit knusperigem Layout zusammenpassen.

Antwort

16

Ich löste dies ohne Crispy Forms zu ändern, indem Sie einen neuen Feldtyp zu schaffen, die eine formset macht:

from crispy_forms.layout import LayoutObject, TEMPLATE_PACK 

class Formset(LayoutObject): 
    """ 
    Layout object. It renders an entire formset, as though it were a Field. 

    Example:: 

    Formset("attached_files_formset") 
    """ 

    template = "%s/formset.html" % TEMPLATE_PACK 

    def __init__(self, formset_name_in_context, template=None): 
     self.formset_name_in_context = formset_name_in_context 

     # crispy_forms/layout.py:302 requires us to have a fields property 
     self.fields = [] 

     # Overrides class variable with an instance level variable 
     if template: 
      self.template = template 

    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK): 
     formset = context[self.formset_name_in_context] 
     return render_to_string(self.template, Context({'wrapper': self, 
      'formset': formset})) 

Es braucht eine Vorlage die formset zu machen, die Ihnen genau die Kontrolle darüber gibt, wie es gemacht hat:

{% load crispy_forms_tags %} 

<div class="formset"> 
    {% crispy formset %} 
    <input type="button" name="add" value="Add another" /> 
</div> 

Sie können es verwenden, um einen Formularsatz in Ihren Layouts wie jedes andere Crispy Layoutelement einzubetten:

self.helper.layout = Layout(
    MultiField(
     "Education", 
     Formset('education'), 
    ), 
+2

Eine geringfügige Änderung, die ich empfehlen würde, ist, einen optionalen Parameter zum Formset LayoutObject für 'formset_helper' hinzuzufügen. Das funktioniert genauso. Auf diese Weise können Sie auch den benutzerdefinierten Helfer übergeben. – Alejandro

+1

In welche Dateien werden diese Codes geschrieben? Wo platziere ich formset.html? Und was ist Formset ("Bildung"); Woher kommt es? –

3

Dies wird derzeit in knusprigen Formen nicht unterstützt. Ihre einzige Option wäre |as_crispy_field Filter (noch nicht dokumentiert, tut mir leid).

I Entwicklung dieses Features für {% crispy %} Tag und in einem Feature-Zweig begonnen habe, es ist alles hier erklärt: https://github.com/maraujop/django-crispy-forms/issues/144

ich für Feedback bin auf der Suche, wenn Sie also immer noch interessiert sind, zu schreiben frei fühlen.

2

Eine geringfügige Änderung der früheren Antwort von qris.

Dieses Update (wie von Alejandro vorgeschlagen) für unser eigenes FormsetLayout-Objekt verwenden, um ein FormHelper Objekt steuern lassen, wie die Felder der formset gerendert werden.

from crispy_forms.layout import LayoutObject 

from django.template.loader import render_to_string 


class Formset(LayoutObject): 
    """ 
    Renders an entire formset, as though it were a Field. 
    Accepts the names (as a string) of formset and helper as they 
    are defined in the context 

    Examples: 
     Formset('contact_formset') 
     Formset('contact_formset', 'contact_formset_helper') 
    """ 

    template = "forms/formset.html" 

    def __init__(self, formset_context_name, helper_context_name=None, 
       template=None, label=None): 

     self.formset_context_name = formset_context_name 
     self.helper_context_name = helper_context_name 

     # crispy_forms/layout.py:302 requires us to have a fields property 
     self.fields = [] 

     # Overrides class variable with an instance level variable 
     if template: 
      self.template = template 

    def render(self, form, form_style, context, **kwargs): 
     formset = context.get(self.formset_context_name) 
     helper = context.get(self.helper_context_name) 
     # closes form prematurely if this isn't explicitly stated 
     if helper: 
      helper.form_tag = False 

     context.update({'formset': formset, 'helper': helper}) 
     return render_to_string(self.template, context.flatten()) 

Vorlage (verwendet formset zu machen):

{% load crispy_forms_tags %} 

<div class="formset"> 
    {% if helper %} 
    {% crispy formset helper %} 
    {% else %} 
    {{ formset|crispy }} 
    {% endif %} 
</div> 

Jetzt kann es wie jedes andere knusprige Formen Layout-Objekt in jedem Layout verwendet werden.

self.helper.layout = Layout(
    Div(
     Field('my_field'), 
     Formset('my_formset'), 
     Button('Add New', 'add-extra-formset-fields'), 
    ), 
) 

# or with a helper 
self.helper.layout = Layout(
    Div(
     Field('my_field'), 
     Formset('my_formset', 'my_formset_helper'), 
     Button('Add New', 'add-extra-formset-fields'), 
    ), 
) 
0

In Anlehnung an obige Lösung Formset (LayoutObject), würden Sie kombinieren django-dynamic-Formset & knusprig.Abschnitt Teil N

Jetzt

  • Auftrag des hinzufügen Dynamic es ist einfach und klar

    • Formen Abschnitt Teil 1
    • Bestellung der Inline-formset mit der Bestellung, ModelForms: Auf meiner Bestellseite Ich habe sind:

      class OrderTestForm(forms.ModelForm): 
      def __init__(self, *args, **kwargs): 
          super(OrderTestForm, self).__init__(*args, **kwargs) 
          self.helper = FormHelper(self) 
          self.helper.form_tag = True 
          self.helper.html5_required = True 
          self.helper.form_action = 'test_main' 
          self.helper.layout = Layout(
           'product_norms', #section 1 
           'reference_other', #section 1 
           # rest of the section 1 fields 
           Formset('samples', 'helper'), # inline dynamic forms 
           'checkbox_is_required' # start of section N 
           # other order sections fields 
          ) 
          self.helper.add_input(Submit("submit", "Save order")) 
      

      Formset Helfer Layout:

      Hinzufügen/Löschen von Inlines, das Speichern von Bestellungen mit Formset-Operationen funktioniert wie erwartet.

  • Verwandte Themen