LoginSignup
46
43

More than 5 years have passed since last update.

Djangoで一つのフォームで複数のモデルを保存する

Last updated at Posted at 2016-12-07

アドベントカレンダーに空白があるので・・・

  • Django 1.10.4
  • Python 3.5.2

この記事の内容

DjangoではForm関係のAPIは割と手厚いのですが、一つのフォームの中で複数のモデルを編集しようとすると、急に面倒度が上がります。

なので、モジュールを使いながら手早くその辺のことができるようにします。

前の記事の続きのようなものです。

インストールするモジュール

django-extra-views

pip install django-extra-views

使い方

django extra viewsはフォームクラスを使わなくても行けるので、そうします。

CreateView

モデル

models.py
from django.db import models


class Person(models.Model):

    name = models.CharField(max_length=255)
    age = models.IntegerField(default=25) # 25歳に戻りたい


class Car(models.Model):

    owner = models.ForeignKey(Person)
    color = models.CharField(max_length=10)

views.py

views.py
from extra_views import CreateWithInlinesView, InlineFormSet


class CarInlineFormSet(InlineFormSet):
    model = Car
    fields = ("color", )
    can_delete = False  # create view では削除不要


class PersonCarCreateFormsetView(CreateWithInlinesView):
    model = Person
    fields = ("name", "age")  # self.model の fields
    inlines = [CarInlineFormSet, ]
    template_name = "person_formset.html"
    success_url = "/"

テンプレート

person_formset.html
{% extends "base.html" %}

{% block content %}

    <form method="post">
        {% csrf_token %}
        <table>
            {{ form.as_table }}
        </table>

                {# インラインはinlinesという変数にリストで入っている #}
        <p>Car Color</p>
        <table>
            {% for form in inlines %}
                {{ form.as_table }}
            {% endfor %}
        </table>
        <button type="submit">save</button>
    </form>

{% endblock %}

UpdateView

モデル

同じ

views.py

views.py
from extra_views import InlineFormSet, UpdateWithInlinesView

class CarInlineFormSetCanDelete(InlineFormSet):
    model = Car
    fields = ("color", )
    can_delete = True

class PersonCarUpdateFormsetView(UpdateWithInlinesView):
    model = Person
    fields = ("name", "age")
    inlines = [CarInlineFormSetCanDelete, ]
    template_name = "person_formset.html"
    success_url = "/"

テンプレート

同じ

まとめ

なかなか便利。


追記 2017-09-27

as_table以外での表示の仕方

普通に書いていると、インラインの方を table.name のように書きたくなる。

ちょっとはまったが、

template.html

{% for inline in inlines %}
  {% for line in inline %}
     {{ line.name }}
  {% endfor %}
{% endfor %}

のように、二重ループすればよい。
inlinesには複数のインラインモデルが設定されているためだと思われる。

追記ここまで


46
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
43