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

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

ただいまの
回答率

90.51%

  • Python 3.x

    6835questions

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

  • Django

    1114questions

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

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

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 274

tarryscoffee

score 5

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

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

 ソースコード

### modele.py

from django.contrib.auth.models import User, AbstractUser
from django.db import models


## Userと1対1
class MetaUser(models.Model):
    user = models.OneToOneField(User, on_delete = models.CASCADE)
    company = models.CharField(max_length = 100)

    def __str__(self):
        return self.company


## Userと多対1
class SuperUser(models.Model):
    user = models.ForeignKey(User, on_delete = models.CASCADE)
    interest = models.CharField(max_length = 100)

    def __str__(self):
        return self.interest


## Userと多対多
class UltraUser(models.Model):
    user = models.ManyToManyField(User)
    benefit = models.CharField(max_length = 100)

    def __str__(self):
        return self.benefit
### forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import MetaUser, SuperUser, UltraUser


class MetaUserForm(forms.ModelForm):
    class Meta:
        model = MetaUser
        fields = ['company'] # ここで'user'は入れない


class SuperUserForm(forms.ModelForm):
    class Meta:
        model = SuperUser
        fields = ['interest'] # ここで'user'は入れない


class UltraUserForm(forms.ModelForm):
    class Meta:
        model = UltraUser
        fields = ['benefit'] # ここで'user'は入れない
### views.py

from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.views import View
from .models import MetaUser
from .forms import MetaUserForm, SuperUserForm, UltraUserForm


def index(request):
    params = {
        'MetaUserForm' : MetaUserForm(),
        'SuperUserForm': SuperUserForm(),
        'UltraUserForm': UltraUserForm(),
    }

    if request.method == 'POST':

        meta = MetaUserForm(request.POST)
        super = SuperUserForm(request.POST)
        ultra = UltraUserForm(request.POST)

        ## 1対1 の登録
        if meta.is_valid():
            meta = meta.save(commit = False)
            meta.user = request.user
            meta.save()

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

        ## 多対多 の登録 / Userの登録をしなくてもOKっぽい
        if ultra.is_valid():
            ultra.save()

    return render(request, 'app1/index.html', params)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>MetaUserForm</h2>

<form action="{% url 'app1:index' %}" method="post">
    <table>
        {% csrf_token %}
        {{MetaUserForm}}
        <tr>
            <td></td>
            <td><input type="submit" value="登録"></td>
        </tr>
    </table>

</form>

<hr>
<h2>SuperUserForm</h2>

<form action="{% url 'app1:index' %}" method="post">
    <table>
        {% csrf_token %}
        {{SuperUserForm}}
        <tr>
            <td></td>
            <td><input type="submit" value="登録"></td>
        </tr>
    </table>

</form>

<hr>
<h2>UltraUserForm</h2>

<form action="{% url 'app1:index' %}" method="post">
    <table>
        {% csrf_token %}
        {{UltraUserForm}}
        <tr>
            <td></td>
            <td><input type="submit" value="登録"></td>
        </tr>
    </table>

</form>

<hr>

</body>
</html>

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

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

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

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

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

## views.py
        if meta.is_valid():
            meta = meta.save(commit = False)
            meta.user = request.user
            meta.save()
##  「登録」ボタンを押下後のエラー
UNIQUE constraint failed: app1_metauser.user_id

というエラーが出てしまい登録ができない

また、forms.pyにおいて、
明示的にfieldsにuserを登録しても画面にエラーは表示されないが、DBに登録もされない

class MetaUserForm(forms.ModelForm):
    class Meta:
        model = MetaUser
        fields = ['user', 'company']

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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

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

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

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

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

        if meta.is_valid():
            if not MetaUser.objects.filter(user=request.user):
                meta = meta.save(commit=False)
                meta.user = request.user
                meta.save()

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/22 21:50

    tatamyiwathyさん

    ありがとうございます!
    まずは「登録」ボタンを押下後のエラーは改善いたしました。

    あとはDBに情報を入力ができればひとまずは大丈夫そうです。
    自分の方でも引き続き調べて見たいと思います!

    キャンセル

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

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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

  • Python 3.x

    6835questions

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

  • Django

    1114questions

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