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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Django

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

Python 3.x

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

Python

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

Q&A

1回答

2122閲覧

1対1のテーブル関係におけるフォーム作成について

tarryscoffee

総合スコア13

Django

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

Python 3.x

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

Python

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

0グッド

0クリップ

投稿2018/07/20 06:35

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

表題についてご質問があります。

現在、Laravel、Djangoどちらかを利用した【集計後に編集可、また、PDFに書き出しのできるアンケートフォーム(会員機能あり)】を作成しています。

イメージ説明
イメージ説明
イメージ説明

前回、別でデータベースのテーブル設計(論理設計)についてでテーブル設計について質問をさせていただきいました。

今回は、そのテーブル設計を元にフォームを作成する場合でつまづいてしまったところがあります。

下記図のように今回のアンケートに必要なテーブルおよび関係は1対1となります。
イメージ説明

テーブル設計は本を見ながら行いましたが、

  • 1ユーザーにつき1pdfしか作成不可
  • pdfテーブルはuser_idを外部キーとしてuserテーブルを参照。最初はuserテーブルにpdf_idを入れていましたが、会員登録直後はpdfテーブルの主キーでもあるpdf_idがNULLになる場合もあるため、userテーブルにはpdf_idを入れずuser_idで紐付けを行いました。
  • pdfとquestion1やquestion2、question3は、それぞれpdfテーブルに対して1つずつのみの対応であるため、それぞれ1対1にしました。

上記のことを意識しながらテーブルを設計をしました。

そして、このテーブルを元にDjangoでソースコードを記述していきました。

ソース

python

1# views.py 2 3from django.db import models 4 5from users.models import User 6 7 8class Pdf(models.Model): 9 id = models.AutoField(primary_key = True) 10 user = models.OneToOneField(User, on_delete = models.CASCADE) 11 created_at = models.DateTimeField(auto_now_add = True) 12 update_at = models.DateTimeField(auto_now = True) 13 14 15class Question1(models.Model): 16 pdf = models.OneToOneField(Pdf, on_delete = models.CASCADE) 17 asking_1 = models.CharField(max_length = 500) 18 asking_2 = models.CharField(max_length = 500) 19 asking_3 = models.CharField(max_length = 500) 20 asking_4 = models.CharField(max_length = 500) 21 asking_5 = models.CharField(max_length = 500) 22 23 24class Question2(models.Model): 25 pdf = models.OneToOneField(Pdf, on_delete = models.CASCADE) 26 asking_1 = models.CharField(max_length = 500) 27 asking_2 = models.CharField(max_length = 500) 28 asking_3 = models.CharField(max_length = 500) 29 asking_4 = models.CharField(max_length = 500) 30 asking_5 = models.CharField(max_length = 500) 31 32 33class Question3(models.Model): 34 pdf = models.OneToOneField(Pdf, on_delete = models.CASCADE) 35 asking_1 = models.CharField(max_length = 500) 36 asking_2 = models.CharField(max_length = 500) 37 asking_3 = models.CharField(max_length = 500) 38 asking_4 = models.CharField(max_length = 500) 39 asking_5 = models.CharField(max_length = 500) 40

python

1# forms.py 2 3from django.contrib.auth import get_user_model 4from django.forms import ModelForm, inlineformset_factory 5 6from .models import (Pdf, Question1, Question2, Question3) 7 8 9class ProcedureForm(ModelForm): 10 class Meta: 11 model = Question1 12 fields = '__all__' 13 14 def __init__(self, *args, **kwargs): 15 super().__init__(*args, **kwargs) 16 for field in self.fields.values(): 17 field.widget.attrs['class'] = 'form-control' 18

python

1# views.py 2 3from django.urls import reverse_lazy, reverse 4from django.views.generic import TemplateView, CreateView, FormView 5 6from pdf.models import Pdf 7from .forms import ProcedureForm 8 9 10# *-----------------------------------------------------* 11# 作成フォーム 12# *-----------------------------------------------------* 13class ProcedureView1(FormView): 14 template_name = 'pdf/procedure_input.html' 15 form_class = ProcedureForm 16 success_url = reverse_lazy('pdf:confirm') 17 18 def get_form(self, form_class = None): 19 """Return an instance of the form to be used in this view.""" 20 21 if self.request.method == 'POST': 22 form_data1 = self.request.POST 23 else: 24 form_data1 = self.request.session.get('form_data1', None) 25 26 return self.form_class(form_data1) 27 28 # form_valid()は、postされた際、validationがOKだった場合に、システムからコールされる関数です。 29 # 保存処理や、後処理、リダイレクト先を設定するために利用します。 30 # 親のform_valid()の実行結果を戻すと、デフォルトのリダイレクト先(success_url)が設定されます。 31 def form_valid(self, form): 32 self.request.session['form_data1'] = self.request.POST 33 return super().form_valid(form) 34 35 36# *-----------------------------------------------------* 37# 確認画面 38# *-----------------------------------------------------* 39class ProcedureConfirm(TemplateView): 40 template_name = 'pdf/procedure_confirm.html' 41 42 def get_context_data(self, **kwargs): 43 context = super().get_context_data(**kwargs) 44 form_data1 = self.request.session.get('form_data1', None) 45 context['form1'] = ProcedureForm(form_data1) 46 return context 47 48 49# *-----------------------------------------------------* 50# 作成完了時処理 51# *-----------------------------------------------------* 52class ProcedureComplete(CreateView): 53 model = Pdf 54 form_class = ProcedureForm 55 success_url = reverse_lazy('accounts:dashboard') # なぜかaccounts:dashboardにとばない 56 57 def get_form(self, form_class = None): 58 form_data1 = self.request.session.pop('form_data1', None) 59 return self.form_class(form_data1) 60

不明点1

入力画面にアクセスをすると、一番上にpdfの選択フォームが表示されてしまいます。
これはテーブル設計上pdf_idと紐づけている(つもり)なので、表示されず自動で値が入って欲しいです。
イメージ説明

一応、下記のようにfieldsを個別に指定をすれば、pdfは表示されませんが、
最後の登録完了画面でエラーが発生します。

python

1# forms.py 2 class Meta: 3 model = Question1 4# fields = '__all__' 5 fields = ['asking_1', 'asking_2', 'asking_3', 'asking_4', 'asking_5', ]
# エラー内容 NOT NULL constraint failed: pdf_question1.pdf_id

ちなみに、forms.pyを

python

1# model = Question1 2 model = Pdf

のように、モデル対象モデルをPdfにすると、今度はユーザー名を選択できるようになってしまいます。
イメージ説明

不明点2

肝心のデータベースへの登録が行われません。(これはテーブル設計に関係がなさそうですね、、。)
データベースの登録はviews.pyで行われていますが、うまくいきません。
(おまけにsuccess_url = reverse_lazy('accounts:dashboard')を指定していても、リダイレクトされない)

python

1# *-----------------------------------------------------* 2# 作成完了時処理 3# *-----------------------------------------------------* 4class ProcedureComplete(CreateView): 5 model = Pdf 6 form_class = ProcedureForm 7 success_url = reverse_lazy('accounts:dashboard') 8 9 def get_form(self, form_class = None): 10 form_data1 = self.request.session.pop('form_data1', None) 11 return self.form_class(form_data1)

以上となりますが、1対多におけるフォーム作成ついてはinlineformset_factoryを使うなど、情報が多く見受けられましたが、1対1についてはあまり存在がしませんでした。
どなたかこの場合はどうすればいいかがわかる方、また見当のつく方がいらっしゃいましたら、ご教授いただけると幸いです。

それではどうぞ宜しくお願いいたします。

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

これはテーブル設計上pdf_idと紐づけている(つもり)なので、表示されず自動で値が入って欲しいです。

  • まずこの時点で、PDFが表示されてないということは、紐づいてるPDFデータが無いことを意味します。まずそこを見直すのが良いと思います。
  • 次に フィールドを表示したくないのであれば HiddenInputなどのウィジェットを使うと、type=hiddenのフィールドになるので、非表示になります。
  • https://docs.djangoproject.com/en/2.0/ref/forms/widgets/#hiddeninput

肝心のデータベースへの登録が行われません。(これはテーブル設計に関係がなさそうですね、、。)
データベースの登録はviews.pyで行われていますが、うまくいきません。

  • 何かエラーなどは出てないのでしょうか? どのようにうまく行かないのか不明なので回答するのが難しいですが、まずは「ProcedureComplete」 という viewが本当に実行されてるのかどうか調べてみるのが良いと思いました。(urls.pyの設定を間違って別のviewが実は呼び出されたとかよくあります。)

投稿2018/07/21 13:22

tell_k

総合スコア2120

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問