@mrkovalchuk
Junior developer

Как делается FormSet для отношения ManyToMany?

Доброго дня.

Зашел в тупик, без Вас не разберусь. Необходимо вывести несколько форм (основной объект и связанные с ним объекты того же типа) на одной странице. Объект завязан сам на себя ManyToMany отношением (ниже будет модель).

Представление, на котором хочу увидеть несколько форм создается с помощью UpdateView и на данный момент выводит одну форму:

c4404badf8.jpg

Хотелось бы, чтобы рядом (и ниже, соответственно) выводилась заполненная форма связанного объекта:

3574a7bf4a.jpg

Почитав различные материалы в сети пришел к выводу, что должна помочь следующая конструкция в forms.py:
PostFormSet = inlineformset_factory(Post, Post.depend_posts.through, fk_name='from_post', form=PostForm, can_delete=False)


Получаю не совсем то, что хотелось бы:

84a8c15ab5.jpg

Template Формы:
<form class="form-horizontal form-label-left" method="post" enctype="multipart/form-data">
                    {% csrf_token %}
                    {{ form_vk.management_form }}
                    {% for form in form_vk %}
                        {% for field in form.visible_fields %}
                            {% if field.auto_id == 'id_date_publish' %}
                                <div class="control-group">
                                    <div class="controls">
                                        <div class="input-prepend input-group">
                                                <span class="add-on input-group-addon"><i
                                                        class="glyphicon glyphicon-calendar fa fa-calendar"></i></span>
                                            {{ field }}
                                        </div>
                                    </div>
                                </div>
                            {% endif %}
                            <div class="form-group">
                                <label class="control-label col-md-3 col-sm-3 col-xs-12"
                                       for="{{ field.auto_id }}">{{ field.label_tag }}</label>
                                <div class="col-md-9 col-sm-9 col-xs-12">
                                    {{ field }}
                                </div>
                                {% if field.errors %}
                                    <div class="control-label">
                                        {{ field.errors.as_text }}
                                    </div>
                                {% endif %}
                            </div>
                        {% endfor %}
                    {% endfor %}
                    <div class="ln_solid"></div>
                    <div class="form-group">
                        <div class="col-md-9 col-sm-9 col-xs-12 col-md-offset-3">
                            <button type="button" class="btn btn-primary">Cancel</button>
                            <button type="reset" class="btn btn-primary">Reset</button>
                            <input type="submit" class="btn btn-success" value="Save"/>
                            <button type="submit" class="btn btn-success"
                                    formaction="{% url 'mainApp:to_vk' object.id %}">Send
                            </button>
                        </div>
                    </div>
                </form>


models.py
class Post(models.Model):
    title = models.CharField(verbose_name='Заголовок', max_length=100, null=False, unique=True)
    content = models.TextField(verbose_name='Текст')
    min_age = models.IntegerField(verbose_name='Возрастной рейтинг', default=0)
    image = models.ImageField(verbose_name='Основное изображене', upload_to='news_image')
    site_source = models.URLField(verbose_name='Сайт источник', max_length=110)
    date_publish = models.DateTimeField('Дата публикации', null=True)
    category = models.ForeignKey(Category, verbose_name='Категория', on_delete=models.CASCADE, default=None)
    publish_status = models.BooleanField(verbose_name='Опубликован', default=False)
    tags = models.ManyToManyField(Tag)
    depend_posts = models.ManyToManyField('self')

    def __str__(self):
        return self.title


views.py
class UpdatePostView(UpdateView):
    model = Post
    form_class = PostForm
    template_name = 'mainApp/post_edit_create.html'
    success_url = '/'

    def get_context_data(self, **kwargs):
        context = super(UpdatePostView, self).get_context_data(**kwargs)
        if self.request.POST:
            context['form_vk'] = PostFormSet(self.request.POST, self.model)
        else:
            context['form_vk'] = PostFormSet()
        return context


А вот таблица, которую сваял Django для MTM
0df70a1f34.jpg
  • Вопрос задан
  • 835 просмотров
Пригласить эксперта
Ответы на вопрос 1
@to_east
Если я правильно понимаю - тебе нужно вывести несколько экземпляров форм с возможностью редактирования, то возможно это поможет(если вопрос актуален еще:)):
# forms.py

class EditThumbsForm(forms.ModelForm):
    class Meta:
        model = Thumb
        fields = ('src', )
    src = forms.CharField()


EditThumbsFormSet = forms.inlineformset_factory(Video, Thumb, form=EditThumbsForm, extra=0)


class EditVideosForm(forms.ModelForm):
    class Meta:
        model = Video
        fields = ('id', 'video_id', 'title', )

    id = forms.IntegerField()
    video_id = forms.IntegerField()
    title = forms.CharField()


class EditVideosModelFormSet(BaseModelFormSet):
    def add_fields(self, form, index):
        super(__class__, self).add_fields(form, index)
        form.thumb_formset = EditThumbsFormSet(
            instance=form.instance,
            data=form.is_bound and form.data or None,
            files=form.is_bound and form.files or None,
            prefix='thumb-%s-%s' % (
                form.prefix,
                EditThumbsFormSet.get_default_prefix()
            )
        )

EditVideosFormSet = forms.modelformset_factory(Video, EditVideosForm, formset=EditVideosModelFormSet, extra=0)

Во вьюхе так:
class EditVideosView(View):
    template_name = 'admin/edit_videos.html'

    def get(self, request):
        instance = Video.objects.all()
        formset = EditVideosFormSet(queryset=instance)
        return render(request, self.template_name, context={'formset': formset})

А в шаблоне примерно так:
{% for form in formset %}
    <li>
        {{ form }}
        {% if form.thumb_formset %}
            {{ form.thumb_formset.management_form }}
            <ul>
            {% for thumb in form.thumb_formset %}
                <li>
                {{ thumb.src }}
                </li>
            {% endfor %}
            </ul>
        {% endif %}
    </li>
{% endfor %}


Если кратко то необходимо вначале создать формсет с основной модели при помощи modelformset_factory(), а потом уже добавлять связанные таблицы к основной при помощи inlineformset_factory()
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы