質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • Python

    9119questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7328questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Django

    1168questions

    DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Djangoで親テーブルに紐づいた子テーブルフォームの作り方

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 310

tarryscoffee

score 5

大変お世話になっております。

現在独学でDjnagoの勉強を進めておりますが、
表題の条件の際のフォームの作り方がいまいちわかりません。

色々ググって作成したみたのが下記ソースコードになります。

 環境

python3.6.5
django2.0

 ソースコード

モデルはPersonalityのみ作成しており、Userクラスに対して1対1の関係を持たせております。

#models.py

from django.contrib.auth import get_user_model
from django.db import models

User = get_user_model()

class Personality(models.Model):
    user = models.OneToOneField(User, on_delete = models.CASCADE)
    nickname = models.CharField(max_length = 255)
#forms.py

from django.contrib.auth import get_user_model
from django.forms import models
from testApp.models import Personality

User = get_user_model()

class UserForm(models.ModelForm):
    class Meta:
        model = User
        # fields = ['nickname']
        fields = '__all__'


class PersonalityForm(models.ModelForm):
    class Meta:
        model = Personality
        fields = ['nickname']
        # fields = '__all__'
#views.py

from django.urls import reverse_lazy
from django.views.generic import CreateView
from testApp.forms import PersonalityForm, UserForm

class PersonalityInput(CreateView):
    template_name = 'user_profile.html'
    success_url = reverse_lazy('testApp:top')
    form_class = PersonalityForm

    def get_form(self, form_class = None):
        if self.request.method == 'POST':
            user_form = UserForm(self.request.POST)
            personality_form = PersonalityForm(self.request.POST)

            if user_form.is_valid() and personality_form.is_valid():
                user = user_form.save(commit = False)
                personality = personality_form.save(commit = False)
                personality.user = user

                return self.form_class(personality)
        else:
            return self.form_class()

 エラー内容

フォームに情報を入力し【送信】ボタンを押下後、次ページで下記のエラーが表示されます。

AttributeError at /
'NoneType' object has no attribute 'is_valid'

色々とググってみても、1つのモデルに対して追加の情報しか出て来ず行き詰ってしまいました。
どなたか解決法がお分かりになる方がいらっしゃいましたら、ご教授いただけると幸いです。

それでは宜しくお願い致します。

  修正後のソースコード(インラインフォームセット利用)

いただいた提案に加え、下記チュートリアルを参考に作成してみましたが、
今度は、DBに情報が追加されない症状が発生しました。
エラーなどは特に出力しておらず、デバックをしてみましたが、
まずform_valid()が実行されていないことがわかりました。

ただ、どうしてform_valid()が実行されないかがわからず、
再度行き詰ってしまいました。。

Django、インラインフォームセットを使う

#forms.py

from django.contrib.auth import get_user_model
from django.forms import ModelForm, inlineformset_factory

from personal.models import PersonalInfo


PersonalInfoFormSet = inlineformset_factory(
        parent_model = get_user_model(),
        model = PersonalInfo,
        fields = ['height', 'weight'],
        extra = 1,
        can_delete = False
)
# views.py

from django.contrib.auth import get_user_model
from django.forms import inlineformset_factory
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import CreateView

from personal.forms import PersonalInfoFormSet
from personal.models import PersonalInfo

User = get_user_model()


class PersonalEdit(CreateView):
    model = User
    fields = '__all__'
    template_name = 'personal/personal_edit.html'
    success_url = reverse_lazy('accounts:dashboard')

    def form_valid(self, form):
        self.object = form.save(commit = False)

        formset = PersonalInfoFormSet(self.request.POST, instance = self.object)

        if formset.is_valid():
            self.object.save()
            formset.save()
            return HttpResponseRedirect(self.get_success_url())

        else:
            return self.render_to_response(self.get_context_data(form = form, formset = formset))

    def get_context_data(self, **kwargs):
        if 'formset' not in kwargs:
            kwargs['formset'] = PersonalInfoFormSet(self.request.POST or None)
        return super().get_context_data(**kwargs)
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

インラインフォームセットが利用できると思います。

インラインフォームセット

インラインフォームセットは、モデルフォームセット上の小さな抽象化レイヤーです。これを使うと、外部キーで関連するオブジェクトを操作することが簡単になります。以下の 2 つのモデルがあるとします:

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)

ある作者 (Author) に紐付いた本 (Book) を編集するフォームセットを作成するには、以下のようにします:

>>> from django.forms import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book, fields=('title',))
>>> author = Author.objects.get(name='Mike Royko')
>>> formset = BookFormSet(instance=author)

 追記

汎用ビューは使ったことがないので、知りませんでしたが、そのままでは、inlineFormsetが使えないようですね・・・

もともと参考にされていたものと、重複しているかもしれませんが、こちらの記事が参考になるように思います。
Django: formset を form に埋め込む

または、inlineFormsetを利用するために汎用ビューに色々書くくらいなら、いっそのこと、通常のview関数を書いて、urlsから呼び出した方が、スッキリするかもしれません。

あと、いまさらですが、urlsに追加した内容や、templateのHTMLも可能な限り掲載してもらうと、何か見つかるかもしれません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/25 13:57

    Meganezaruさん

    お忙しい中、ご提案いただき誠にありがとうございます。
    インラインフォームセットを利用してみましたが、やはりうまくいきません。。

    修正後のソースコードど症状を追記しましたので、もし改善点がお分かりになれば
    ご教授いただけると幸いです。

    キャンセル

  • 2018/07/26 09:29

    回答に追記しました。

    キャンセル

同じタグがついた質問を見る

  • Python

    9119questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7328questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Django

    1168questions

    DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。