Django extra views

Exemple formsets django

Django extra views” ens proporciona una manera fàcil, a través de les seves vistes “vitaminades”, d’implementar els “formsets” per tal d’editar les relacions 1-n amb Django. Tambe tenir django-formset-js que ens “dinamitza” a través de Javascript la inserció i eliminació de tuples dels “formsets”.

Per instal.lar les “django extra views” cal executar:

pip install django-extra-views

Per instal.lar django-formset-js cal executar:

pip install django-formset-js

i afegir l’aplicació al projecte:

INSTALLED_APPS = (
    ...
    'djangoformsetjs',
)

Detallant els passos, que serien:
Views:

# -*- encoding: utf-8 -*-

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout
from crispy_forms.layout import Div

from django import forms

from extra_views import CreateWithInlinesView, UpdateWithInlinesView, InlineFormSet
from backoffice.cars.models import AssuranceFeaturePrice, EquipmentPrice, ChargePrice
from cms.cmscars.office.forms import AssuranceFeaturePriceForm, EquipmentPriceForm, ChargePriceForm

#########
# views #
#########

class AssuranceFeaturePricesInline(InlineFormSet):
    model = AssuranceFeaturePrice
    form_class = AssuranceFeaturePriceForm
    extra = 0


class EquipmentPricesInline(InlineFormSet):
    model = EquipmentPrice
    form_class = EquipmentPriceForm
    extra = 0


class ChargePricesInline(InlineFormSet):
    model = ChargePrice
    form_class = ChargePriceForm
    extra = 0


class OfficeCreateView(CreateWithInlinesView):
    inlines = [AssuranceFeaturePricesInline, EquipmentPricesInline, ChargePricesInline]
    pass


class OfficeUpdateView(UpdateWithInlinesView):
    inlines = [AssuranceFeaturePricesInline, EquipmentPricesInline, ChargePricesInline]
    pass

Forms:

class AssuranceFeaturePriceForm(forms.ModelForm):

    class Meta:
        model = AssuranceFeaturePrice
        fields = ('id', 'office', 'feature', 'price')

    @property
    def helper(self):
        helper = FormHelper()
        helper.label_class = 'col-xs-4'
        helper.field_class = 'col-xs-6'
        helper.form_tag = False
        helper.layout = Layout(
            'id', 'office', 'feature', 'price',
            Div('DELETE', css_class='hidden')
        )
        return helper


class EquipmentPriceForm(forms.ModelForm):

    class Meta:
        model = EquipmentPrice
        fields = ('id', 'office', 'equipment', 'price')

    @property
    def helper(self):
        helper = FormHelper()
        helper.label_class = 'col-xs-4'
        helper.field_class = 'col-xs-6'
        helper.form_tag = False
        helper.layout = Layout(
            'id', 'office', 'equipment', 'price',
            Div('DELETE', css_class='hidden')
        )
        return helper


class ChargePriceForm(forms.ModelForm):

    class Meta:
        model = ChargePrice
        fields = ('id', 'office', 'charge', 'price')

    @property
    def helper(self):
        helper = FormHelper()
        helper.label_class = 'col-xs-4'
        helper.field_class = 'col-xs-6'
        helper.form_tag = False
        helper.layout = Layout(
            'id', 'office', 'charge', 'price',
            Div('DELETE', css_class='hidden')
        )
        return helper

Template:

############
# template #
############

{% block content2 %}
    {{ form.media }}

<form id="form-office" method="post" action="{% if object %}{% url update_url smydestination object.pk %}{% else %}{% url create_url smydestination %}{% endif %}" class="form-horizontal">
        {{ form.errors }}
        {% crispy form %}
        <!-- formsets -->

<div id="initial-precios" class="x_panel col-md-offset-2 col-md-7">
            {% for formset in inlines %}

<div id="container-{{ formset.prefix }}">

<div class="x_title">

<h4>{% show_formset_name formset %}</h4>

                    </div>


<div class="formset well" data-formset-prefix="{{ formset.prefix }}">

<div class="errors">{{ formset.non_form_errors }}</div>

                        {{ formset.management_form }}

<div data-formset-body>
                            {% for item in formset %}

<div class="formset_item form-inline" data-formset-form>
                                    {% crispy item %}
                                    <button type="button" data-formset-delete-button class="btn btn-danger pull-right"><i class="fa fa-trash"></i> {% trans 'Borrar' %}</button>
                                </div>

                            {% endfor %}
                        </div>

                        <script type="form-template" data-formset-empty-form>
                        {% escapescript %}

<div class="formset_item form-inline" data-formset-form>
                                {% crispy formset.empty_form %}
                                <button type="button" data-formset-delete-button class="btn btn-danger pull-right"><i class="fa fa-trash"></i> {% trans 'Borrar' %}</button>
                            </div>

                        {% endescapescript %}
                        </script>
                        <a class="btn btn-success" data-formset-add>
                            <i class="fa fa-plus-square-o"></i> {% trans 'Añadir registro' %}
                        </a>
                    </div>

                </div>

            {% endfor %}
        </div>

        <!-- fin formsets -->
    </form>

{% endblock content2 %}

{% block extrajs %}
    <script type="text/javascript" src="{% static 'js/jquery.formset.min.js' %}"></script>
    <script type="text/javascript">
        //<![CDATA[ $(function($) { $(".formset").formset({ animateForms: true, reorderMode: 'none', }); }); //]]>
    </script>
{% endblock %}

A aquest exemple també es fa ús de Crispy Forms, per tal de millorar l’aparença dels formularis. Per instal.lar-ho:

pip install --upgrade django-crispy-forms

i afegir l’aplicació al projecte:

INSTALLED_APPS = (
    ...
    'crispy_forms',
)

En aquest cas hi ha varis “formsets” relacionats amb el model principal. Per qüestió d’usabilitat s’ha implementat el formset dins un “Tab” del formulari principal. L’exemple exposat queda segons es mostra a l’imatge.

captura_formsets_cropped

Per aprofondir en els paquets citats a l’exemple es recomana visitar els enllaços als mateixos.

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *