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

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

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

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

Python 3.x

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

Python

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

Q&A

解決済

2回答

1396閲覧

OneToOneFieldの使い方について

退会済みユーザー

退会済みユーザー

総合スコア0

Django

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

Python 3.x

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

Python

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

0グッド

0クリップ

投稿2019/04/07 00:38

先日、こちらで質問し、また疑問が生まれたので改めて質問しようと思った次第です。

##聞きたいこと
現在、modelにOneToOneFieldを持たせています。
しかし、CreateViewによって、別objectとしての新規作成ができてしまいます。
その原因と改善方法が知りたいです。

また、私が実装したい機能に対し、そもそもの書き方が間違っているのではないかという不安もあります。ご意見いただければ幸いです。

##実装したいこと
Twitter認証でログインしたユーザが、メモを作成し公開すること。
ただし、メモは一つのみ作成可能。
メモは編集による上書き・削除が可能。

##私がこれまで行なったこと
1.social-auth-app-djangoによるtwitterログイン機能の実装
こちらを参考にし、それ以外に何も記述はしていません。
twitterログイン以外のログイン機能はつけないので、他にUserモデルは必要ないという認識をしています。(ここが間違いなのでしょうか)

2.モデルの作成
ユーザとモデルを一対一の関係になるようにしているつもりです。

import uuid from django.contrib.auth.models import User from django.db import models class Memo(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, null=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=20) content = models.TextField(max_length=5000) image = models.ImageField(upload_to=get_memo_image_path, null=True, blank=True) posted_date = models.DateTimeField(auto_now=True)

3.View作成

#views.py from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse_lazy from django.views.generic import TemplateView, DetailView, CreateView, UpdateView, DeleteView from .forms import MemoForm from .models import Memo class IndexView(TemplateView): template_name = 'index.html' class MemoDetailView(DetailView): model = Memo class MemoCreateView(LoginRequiredMixin, CreateView): model = Memo form_class = MemoForm def get_success_url(self): return reverse_lazy('detail', kwargs={'pk': Memo.id}) login_url = '/login' class MemoUpdateView(LoginRequiredMixin, UpdateView): model = Memo form_class = MemoForm login_url = '/login' def get_success_url(self): url = reverse_lazy("detail", kwargs={"pk": Memo.id}) return url class MemoDeleteView(LoginRequiredMixin, DeleteView): model = Memo success_url = reverse_lazy("index") login_url = '/login'

##余談
質問に関連する余談ですが、model.pyでのuuidをprimaryKeyとしたurlにアクセスできないのです。
これはどういうことなのでしょうか?(別問題でしたら改めて質問します)

#url.py urlpatterns = [ path('', IndexView.as_view(), name="index"), path('<uuid:pk>', MemoDetailView.as_view(), name="detail"), path('<uuid:pk>/update', MemoUpdateView.as_view(), name="update"), path('<uuid:pk>/delete', MemoDeleteView.as_view(), name="delete"), path('create/', MemoCreateView.as_view(), name="create"), path('admin/', admin.site.urls), path('', include('social_django.urls', namespace='social')), ]

上記view.pyのCreateViewにてurlを作成しているイメージです。
そこでhtmlは、

html

1<a class="btn btn-outline-primary" href="{% url 'detail' object.id %}">確認する</a>

と、記述すれど

NoReverseMatch at /create/ Reverse for 'detail' with keyword arguments '{'pk': <django.db.models.query_utils.DeferredAttribute object at 0x10e83d860>}' not found. 1 pattern(s) tried: ['(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$']

このようなエラーメッセージがでます。

以上になります。
そもそも論でも構いません。ご教授お願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

現在、modelにOneToOneFieldを持たせています。
しかし、CreateViewによって、別objectとしての新規作成ができてしまいます。
その原因と改善方法が知りたいです。

これは、同一のユーザで CreateView を複数回使ってもエラーが出ずにいくつも Memo レコードが作れてしまう、という状況だと理解しましたが、この理解で正しいですか?

MemoForm の実装を見せていただかないと正確にはわかりませんが、パッと見の印象では Memo model の user フィールドを null=True とされているので user フィールドが空の memo オブジェクトが複数作れてしまうから、ではないでしょうか。

改善方法については、まず null=True を辞めて、あとは MemoCreateView のところで、同一のユーザに対して複数の memo が作れないようにブロックするとよいのではないでしょうか。アプローチはいろいろあると思いますが、基本は「対象のユーザに対して memo が存在するかどうかをチェックして、存在するときはフォームが送信できない・送信を受け付けないようにする」になるかと思います。

(余談については別問題だと思いますので、この回答ではメインの問題の解消に専念します)

追記 1

上記エラーについてご意見をいただけないでしょうか?

そうですね、 OneToOneField を使っているときに「 NOT NULL constraint failed 」というエラーが出た場合の解決策は、必ずしも null=True とすることではありません。

おそらく今回の場合は MemoCreateView の中で memo オブジェクトを永続化するときに user フィールドを適切にセットされていないために起こっているのではないかと思いますが、満たすべき仕様と問題の実態にあわせて適切な解決策を採る必要があるものと思います。

ちなみに、 model object の関連フィールドにカレントユーザをセットするには、次のページで紹介されているようなコードを記述する必要があります(あくまでもいちサンプルです)。

投稿2019/04/10 06:55

編集2019/04/10 12:27
gh640

総合スコア1407

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

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

退会済みユーザー

退会済みユーザー

2019/04/10 09:27

回答ありがとうございます。 >これは、同一のユーザで CreateView を複数回使ってもエラーが出ずにいくつも Memo レコードが作れてしまう、という状況だと理解しましたが、この理解で正しいですか? はい、その通りです。 また、userフィールドにnull=Trueとした理由としては、エラー文で、 IntegrityError at /create/ NOT NULL constraint failed: memo_memo.user_id が発生し、こちら(http://nihaoshijie.hatenadiary.jp/entry/2014/06/12/090008)を参考にしたことからです。そしてnull=Trueを指定すると余談部分のエラーが発生するという状態です。 今後の方針としては、アドバイス通りCreateViewを変更する予定ですが、上記エラーについてご意見をいただけないでしょうか?
gh640

2019/04/10 12:27

> 上記エラーについてご意見をいただけないでしょうか? 追記で回答させていただきました。ご覧になってみてください :D
退会済みユーザー

退会済みユーザー

2019/04/14 08:55

ありがとうございます。 その後別のエラーも出てしまい、戸惑いましたが、余談を含め全て解決しました。 これから精進します。
gh640

2019/04/15 10:59

そうでしたか。それはよかったです!ぜひがんばってください :D
guest

0

CreateViewで作成したデータ(detailview)にすぐにリンクで飛ばそうとする場合、views.pyファイルでreverse_lazyを使うんのではなく、models.pyファイルの中でget_absolute_urlを使わないといけないようです。

models.pyファイルのMemoに
def get_absolute_url(self):
reverse('detail', kwargs={'pk':object.pk})
と書くとうまくいくかと思います。

投稿2019/04/07 06:55

ryotax

総合スコア142

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

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

退会済みユーザー

退会済みユーザー

2019/04/10 04:49

ありがとうございます。 いただいた回答を参考に試行錯誤しましたが、エラーの解決には至りませんでした。 url部分についてはまた別途考えようと思います。(モデル関連のエラーだと考えているため)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問