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

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

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

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

Python 3.x

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

Q&A

解決済

1回答

385閲覧

Djangoにおけるリレーション関係でつまづいた

tarryscoffee

総合スコア13

Django

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

Python 3.x

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

0グッド

0クリップ

投稿2018/06/22 05:17

いつも拝見させていただいております。

Djangoについてお聞きしたいことがあります。
現在Djangoを用いてwebアプリの開発をしようと思い、まずは使用を確認するために色々といじっていたのですが、DBのリレーション関連でつまづいてしまったところがあります。
SQLはわかりますが、DB自体の知識がありまりないので、それ故にはまっているかもしれません。
下記に使用している環境・ソースコード・エラー内容を記述します。
解決したい事は1対1におけるエラーの原因究明と改善です・

検証内容

Userテーブルに対して、多対多(UltraUser)、多対1(SuperUser)、1対1(MetaUser)のモデルを作成し、
htmlフォームからそれぞれのテーブルに値を格納するまでの実装方法の確認

イメージ説明

環境

macOS high sierra
python3.6
Django2.0
Pycharm
DB : sllite3

ソースコード

python

1### modele.py 2 3from django.contrib.auth.models import User, AbstractUser 4from django.db import models 5 6 7## Userと1対1 8class MetaUser(models.Model): 9 user = models.OneToOneField(User, on_delete = models.CASCADE) 10 company = models.CharField(max_length = 100) 11 12 def __str__(self): 13 return self.company 14 15 16## Userと多対1 17class SuperUser(models.Model): 18 user = models.ForeignKey(User, on_delete = models.CASCADE) 19 interest = models.CharField(max_length = 100) 20 21 def __str__(self): 22 return self.interest 23 24 25## Userと多対多 26class UltraUser(models.Model): 27 user = models.ManyToManyField(User) 28 benefit = models.CharField(max_length = 100) 29 30 def __str__(self): 31 return self.benefit 32

python

1### forms.py 2 3from django import forms 4from django.contrib.auth.forms import UserCreationForm 5from django.contrib.auth.models import User 6from .models import MetaUser, SuperUser, UltraUser 7 8 9class MetaUserForm(forms.ModelForm): 10 class Meta: 11 model = MetaUser 12 fields = ['company'] # ここで'user'は入れない 13 14 15class SuperUserForm(forms.ModelForm): 16 class Meta: 17 model = SuperUser 18 fields = ['interest'] # ここで'user'は入れない 19 20 21class UltraUserForm(forms.ModelForm): 22 class Meta: 23 model = UltraUser 24 fields = ['benefit'] # ここで'user'は入れない 25

python

1### views.py 2 3from django.contrib.auth import get_user_model 4from django.contrib.auth.decorators import login_required 5from django.contrib.auth.models import User 6from django.http import HttpResponse 7from django.shortcuts import render, redirect 8from django.views import View 9from .models import MetaUser 10from .forms import MetaUserForm, SuperUserForm, UltraUserForm 11 12 13def index(request): 14 params = { 15 'MetaUserForm' : MetaUserForm(), 16 'SuperUserForm': SuperUserForm(), 17 'UltraUserForm': UltraUserForm(), 18 } 19 20 if request.method == 'POST': 21 22 meta = MetaUserForm(request.POST) 23 super = SuperUserForm(request.POST) 24 ultra = UltraUserForm(request.POST) 25 26 ## 1対1 の登録 27 if meta.is_valid(): 28 meta = meta.save(commit = False) 29 meta.user = request.user 30 meta.save() 31 32 ## 多対1 の登録 33 if super.is_valid(): 34 super = super.save(commit = False) # DBに保存せずにsuperにモデルを格納 35 super.user = request.user # ログイン中のuserを登録 36 super.save() 37 38 ## 多対多 の登録 / Userの登録をしなくてもOKっぽい 39 if ultra.is_valid(): 40 ultra.save() 41 42 return render(request, 'app1/index.html', params) 43

html

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6</head> 7<body> 8 9<h2>MetaUserForm</h2> 10 11<form action="{% url 'app1:index' %}" method="post"> 12 <table> 13 {% csrf_token %} 14 {{MetaUserForm}} 15 <tr> 16 <td></td> 17 <td><input type="submit" value="登録"></td> 18 </tr> 19 </table> 20 21</form> 22 23<hr> 24<h2>SuperUserForm</h2> 25 26<form action="{% url 'app1:index' %}" method="post"> 27 <table> 28 {% csrf_token %} 29 {{SuperUserForm}} 30 <tr> 31 <td></td> 32 <td><input type="submit" value="登録"></td> 33 </tr> 34 </table> 35 36</form> 37 38<hr> 39<h2>UltraUserForm</h2> 40 41<form action="{% url 'app1:index' %}" method="post"> 42 <table> 43 {% csrf_token %} 44 {{UltraUserForm}} 45 <tr> 46 <td></td> 47 <td><input type="submit" value="登録"></td> 48 </tr> 49 </table> 50 51</form> 52 53<hr> 54 55</body> 56</html>

それぞれの検証結果/エラー内容

【多対多】
models.py以外の箇所で明示的にUserモデルと紐付けをする必要はない

【多対1】
views.pyにて下記コードで登録可能

python

1 super = super.save(commit = False) # DBに保存せずにsuperにモデルを格納 2 super.user = request.user # ログイン中のuserを登録 3 super.save()

【1対1】
【多対1】と同じようにviews.pyで下記コードで実装可能かと思ったが、エラーが出てしまう

python

1## views.py 2 if meta.is_valid(): 3 meta = meta.save(commit = False) 4 meta.user = request.user 5 meta.save()
## 「登録」ボタンを押下後のエラー UNIQUE constraint failed: app1_metauser.user_id ```というエラーが出てしまい登録ができない また、forms.pyにおいて、 明示的にfieldsにuserを登録しても画面にエラーは表示されないが、DBに登録もされない ```python class MetaUserForm(forms.ModelForm): class Meta: model = MetaUser fields = ['user', 'company']

以上となります。
何か見落としていることがあれば、ご教授のほど宜しくお願いたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

すみません。一部の質問のみへの回答です。

python

1## 「登録」ボタンを押下後のエラー 2UNIQUE constraint failed: app1_metauser.user_id

このエラーは一つのUserに対してMetaUserの二つ目が作られるときに発生します。
データベースがまっさらな状態でMetaUserFormの「登録」をクリックしたときはエラーにならず、
2回目に「登録」をクリックしたときに発生していませんか?

こんな感じでMetaUserにすでにユーザーがいないか確認すればエラーは回避できます。

python

1 if meta.is_valid(): 2 if not MetaUser.objects.filter(user=request.user): 3 meta = meta.save(commit=False) 4 meta.user = request.user 5 meta.save()

投稿2018/06/22 08:10

tatamyiwathy

総合スコア1039

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

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

tarryscoffee

2018/06/22 12:50

tatamyiwathyさん ありがとうございます! まずは「登録」ボタンを押下後のエラーは改善いたしました。 あとはDBに情報を入力ができればひとまずは大丈夫そうです。 自分の方でも引き続き調べて見たいと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問