Django Crispy 表单集 CSS

Django Crispy Formsets CSS

我正在尝试将 crispy 表单和 bootstrap 与表单集一起使用,但我似乎无法弄清楚 CSS 样式。我需要在后端设置样式,因为我想让客户端 dynamically add more 具有相同的表单,当您将空表单添加到 HTML 时,它不会保持相同的样式。

create.html

{% load crispy_forms_tags %}
<!--RECIPE INGREDIENTS-->
{% if formset %}
<h3>Ingredients</h3>
{{ formset.management_form|crispy }}

<div id='ingredient-form-list'>
    {% for ingredient in formset %}
        <div class='ingredient-form row'>
    
            {{ ingredient|crispy }}

        
        </div>
    {% endfor %}
</div>

forms.py

class RecipeIngredientForm(forms.ModelForm):
class Meta:
    model = RecipeIngredient
    fields = ['name', 'quantity', 'unit', 'description']
    labels = {
        'name': "Ingredient",
        "quantity:": "Ingredient Quantity",
        "unit": "Unit",
        "description:": "Ingredient Description"}
    

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.helper = FormHelper()
    self.helper.layout = Layout(
        Row(
            Column('name', css_class='form-group col-md-6 mb-0'),
            Column('quantity', css_class='form-group col-md-4 mb-0'),
            Column('unit', css_class='form-group col-md-4 mb-0'),
            css_class='form-row'
        ),
        Row(
            Column('description', css_class='form-group col-md-6 mb-0'),
            css_class='form-row'
        ),
    )

views.py

def recipe_create_view(request):
    form = RecipeForm(request.POST or None)
    RecipeIngredientFormset = formset_factory(RecipeIngredientForm)
    formset = RecipeIngredientFormset(request.POST or None)
    
    context = {
        "form": form,
        "formset": formset,
    }
    if request.method == "POST":
        #print(request.POST)
        if form.is_valid() and formset.is_valid() and instructionFormset.is_valid():
            parent = form.save(commit=False)
            parent.user = request.user
            parent.save()
            
            #recipe ingredients
            for form in formset:
                child = form.save(commit=False)
                if form.instance.name.strip() == '':
                    pass
                else:
                    child.recipe = parent
                    child.save()
            
    else:
        form = RecipeForm(request.POST or None)
        formset = RecipeIngredientFormset()
        
    return render(request, "recipes/create.html", context)

这就是它的呈现方式,并且有一个空的 div 包装了表单的输入字段。我的 FormHelper CSS 不见了。

您需要加载crispy标签,同时在模板中加载crispy表单字段。

当我们现在渲染表单时使用:

{% load crispy_forms_tags %}
{% crispy example_form %}

或者你的情况

{{ ingredient|crispy }}

编辑#4

最初的问题是由于我在 create.html 模板中呈现表单的方式。如 documentation 所示,更好的加载方式是使用 {% crispy ..... %},如下所示 for loop 和空形式。但是,将额外表单呈现为 {% crispy formset.empty_form %} 会导致问题,因为它会生成一个全新的 <form>,因此对于额外表单,我设法在模板中使用 CSS 手动呈现它。这可能绝不是最好的方法,但是,唉,它有效。

请参阅下面的更新文件:

forms.py

class RecipeIngredientForm(forms.ModelForm):
class Meta:
    model = RecipeIngredient
    fields = ['name', 'quantity', 'unit', 'description']
    labels = {
        'name': "Ingredient",
        "quantity:": "Ingredient Quantity",
        "unit": "Unit",
        "description:": "Ingredient Description"}
    

def __init__(self, *args, **kwargs):
    super(RecipeIngredientForm, self).__init__(*args, **kwargs)

    self.helper = FormHelper()
    self.helper.form_id = 'id-entryform'
    self.helper.form_class = 'form-inline'
    self.helper.layout = Layout(
        Div(
            Div(Field("name", placeholder="Chickpeas"), css_class='col-6 col-lg-4'),
            Div(Field("quantity", placeholder="2 x 400"), css_class='col-6 col-md-4'),
            Div(Field("unit", placeholder="grams"), css_class='col-5 col-md-4'),
            Div(Field("description", placeholder="No added salt tins"), css_class='col-12'),
        
        css_class="row",
       ),
       
    )

create.html

<!--RECIPE INGREDIENTS-->
                {% if formset %}
                    <h3>Ingredients</h3>
                    {{ formset.management_form|crispy }}
                    {% load crispy_forms_tags %}
                    <div id='ingredient-form-list'>
                        {% for ingredient in formset %}
                       
                                <div class='ingredient-form'>
                                    
                                    {% crispy ingredient %}
                                    
                                </div>
                        {% endfor %}
                    </div>

                    <div id='empty-form' class='hidden'>
                        <div class="row">
                            <div class="col-6">{{ formset.empty_form.name|as_crispy_field }}</div>
                            <div class="col-6">{{ formset.empty_form.quantity|as_crispy_field }}</div>
                            <div class="col-6">{{ formset.empty_form.unit|as_crispy_field }}</div>
                            <div class="col-6">{{ formset.empty_form.description|as_crispy_field }}</div>
                        </div>
                    </div>
                    <button class="btn btn-success" id='add-more' type='button'>Add more ingredients</button>
                {% endif %}
<script>
//ingredients add form
const addMoreBtn = document.getElementById('add-more')
const totalNewForms = document.getElementById('id_ingredient-TOTAL_FORMS')

addMoreBtn.addEventListener('click', add_new_form)
function add_new_form(event) {
    if (event) {
        event.preventDefault()
    }
    const currentIngredientForms = document.getElementsByClassName('ingredient-form')
    const currentFormCount = currentIngredientForms.length // + 1
    const formCopyTarget = document.getElementById('ingredient-form-list')
    const copyEmptyFormEl = document.getElementById('empty-form').cloneNode(true)
    copyEmptyFormEl.setAttribute('class', 'ingredient-form')
    copyEmptyFormEl.setAttribute('id', `ingredient-${currentFormCount}`)
    const regex = new RegExp('__prefix__', 'g')
    copyEmptyFormEl.innerHTML = copyEmptyFormEl.innerHTML.replace(regex, currentFormCount)
    totalNewForms.setAttribute('value', currentFormCount + 1)
    // now add new empty form element to our html form
    formCopyTarget.append(copyEmptyFormEl)
}