Вложенные формы в Джанго

Многие разработчики рано или поздно сталкиваются с такой проблемой как вложенные формы. Для начала разберемся для чего вообще они нужны. Представим, что у нас есть модель заказа, у которой должно быть поле, в которое нам необходимо кидать файлы или изображения. Вы скажете, что это делается легко нужно просто добавить поле "FileField". Да это так, но что если нам нужно размножить это поле, т.е. дать пользователю возможность кликом мыши добавить еще несколько полей FileField. Делается это просто с помощью вложеных форм и немного магии. Использовать будем CBV.

 

 

Возьмем к примеру две модели:

 

 

class Company(models.Model):

    user = models.ForeignKey(User, verbose_name=u'Пользователь')

    info = models.CharField(max_length=300, verbose_name=u'Информация о компании', blank=True)

    title = models.CharField(max_length=100, verbose_name=u'Название компании')

    url = models.CharField(max_length=100, verbose_name=u'Ссылка на сайт')

    location = models.CharField(max_length=140, verbose_name=u'Город')




    class Meta:

        verbose_name = u'Копания'

        verbose_name_plural = u'Компании'

 

 

    def __unicode__(self):

        return u'%s' % self.title

 

 



class CompanyImage(models.Model):

    description = models.CharField(max_length=200, verbose_name=u'Описание')

    file_up = models.FileField(upload_to='images/company',blank=True, verbose_name=u'Фотографии')

    order = models.ForeignKey(Company, verbose_name=u'Фото компании')

    class Meta:

        verbose_name = u'Фото компании'

        verbose_name_plural = u'Фото'

 

 

    def __unicode__(self):

        return u'%s' % self.id

 

 

Модель компании и модель файлов компании. 

 

 

Задача сделать форму создания компании, где есть поля загрузки файла и его описания. Поля файла и описания можно добавить прям в форме или удалить. Т.е. нам нужно сделать вложенную форму.

 

 

Приступим. Создадим forms.py:

 

 

class AddCompanyForm(forms.ModelForm):

     class Meta:

         model = Company

         fields = '__all__'

         exclude = ['user']

 

 

Почему исключаем user, потому что он заполнчется автоматически  текущим зарегестрированным пользователем при сохранении.

 

 



CompanyFormSet = inlineformset_factory(Company, CompanyImage, fields = '__all__')

 

 

Создадим views.py:

 

 

class CompanyCreate(CreateView):

      model = Company

      template_name = 'add_company.html'

      form_class = AddCompanyForm

      success_url = '/companies'



     def get(self, request, *args, **kwargs):

        self.object = None

        form_class = self.get_form_class()

        form = self.get_form(form_class)

        company_form = CompanyFormSet()

        return self.render_to_response(

                    self.get_context_data(form=form,

                                        company_form=company_form))
       

 

 

    def post(self, request, *args, **kwargs):

        self.object = None

        form_class = self.get_form_class()

        form = self.get_form(form_class)

        company_form = CompanyFormSet(self.request.POST, self.request.FILES)

        if (form.is_valid() and company_form.is_valid()):

            return self.form_valid(form, company_form)

        else:

            return self.render_to_response(self.get_context_data(form=form,company_form=company_form))
       

 

 

    def form_valid(self, form, company_form):

        form.instance.user = self.request.user

        self.object = form.save()

        company_form.instance = self.object

        company_form.save()

        return HttpResponseRedirect(self.get_success_url())

 

 

В шалоне прописываем следующее:

 

 

{%extends 'base.html'%}

{%block content%}

   <h3>Добавление компании</h3>

   <form action="" method="post" enctype="multipart/form-data">

      {% csrf_token %}

      {{ form.as_p }}

      <fieldset>

      {{ company_form.management_form }}

      {{ company_form.non_form_errors }}

      {% for form in company_form %}

          <div class="inline {{ company_form.prefix }}">

              {{form}}
          </div>

      {% endfor %}

      </fieldset><button class="btn btn-primary" type="submit" name="submit">Добавить</button>

    </form>

{%endblock%}

 

 

В url.py:

 

 

url(r'^company/add/$', CompanyCreate.as_view()),

 

 

Ну вот собственно вложенная форма готова, но у нее нет возможности добавить или удалить вложенные поля. Добавить эту функцию можно с помощью django-dynamic-formset берем оттуда, только нужный скрипт. Пропишем в шаблоне:

 

 

<script src="{{ STATIC_URL }}js/jquery.min.js"></script>
    <script src="{{ STATIC_URL }}js/jquery.formset.js"></script>
    <script type="text/javascript">
        $(function() {
            $(".inline.{{ ingredient_form.prefix }}").formset({
                prefix: "{{ ingredient_form.prefix }}",
            })
            $(".inline.{{ instruction_form.prefix }}").formset({
                prefix: "{{ instruction_form.prefix }}",
            })
        })
    </script>

 

 

Теперь появяться кнопки добавить и удалить.

Адрес веб студии
Позвонить

Городской: +7(8793)33-16-17
Мобильный: +7(928)911-74-69

email веб студии
Написать

manager@kmv-it.ru

Доехать до веб студии
Приехать

г.Пятигорск переулок Первомайский 18

Логотип Кухня сайтов