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

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

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

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

Python

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

Q&A

0回答

417閲覧

Django: ManyToManyFieldで結び付けられたモデルが存在しない状態でも、管理サイトで登録できるようにしたい

kensoon

総合スコア48

Django

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

Python

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

0グッド

0クリップ

投稿2021/06/29 13:17

編集2021/07/01 03:51

補足情報(FW/ツールのバージョンなど)

django 2.2.5
Python 3.7.9

前提・実現したいこと

Djangoで英単語の使い分けの学習をサポートするWebアプリケーションを作成しています。現在構想しているのは、以下のように例文と英単語が存在している状態で、両者の間に品詞と日本語が存在している状態のデータベースです。

モデルイメージ図

上の例だと、まず例文として"You made me happy."と"You made for his home."がある上で、英単語のmakeの使い分けを「動詞: 進む」と「動詞: ~にする」として図示している状態になります。

自分は例文と英単語のM:N対応だと考えたので、発行日や難易度などを追加した上で以下のようなモデルを作成しました。

python:

1# models.py 2import datetime 3 4from django.db import models 5from django.utils import timezone 6 7# Create your models here. 8class EnglishWord(models.Model): 9 """ 10 英語 11 """ 12 spell = models.CharField(max_length=50) 13 difficulty = models.IntegerField(default=0) 14 pub_date = models.DateTimeField('date published', default=timezone.now) 15 16 def __str__(self): 17 return self.spell 18 19 def was_published_recently(self): 20 now = timezone.now() 21 return now - datetime.timedelta(days=1) <= self.pub_date <= now 22 23 was_published_recently.admin_order_field = 'pub_date' 24 was_published_recently.boolean = True 25 was_published_recently.short_description = 'Published Recently?' 26 27class ExampleSentence(models.Model): 28 """ 29 例文 30 """ 31 sentence = models.TextField() 32 english_words = models.ManyToManyField( 33 "EnglishWord", 34 through="EnglishWordExampleSentenceRelation", 35 ) 36 difficulty = models.IntegerField(default=0) 37 pub_date = models.DateTimeField('date published', default=timezone.now) 38 39 def __str__(self): 40 return self.sentence 41 42 def was_published_recently(self): 43 now = timezone.now() 44 return now - datetime.timedelta(days=1) <= self.pub_date <= now 45 46 was_published_recently.admin_order_field = 'pub_date' 47 was_published_recently.boolean = True 48 was_published_recently.short_description = 'Published Recently?' 49 50class EnglishWordExampleSentenceRelation(models.Model): 51 """ 52 英語と例文の中間テーブル 53 """ 54 # 品詞 55 PART_OF_SPEECH = ( 56 ("NOU", "名詞"), 57 ("PRO", "代名詞"), 58 ("ADJ", "形容詞"), 59 ("VER", "動詞"), 60 ("ADV", "副詞"), 61 ("PRE", "前置詞"), 62 ("CON", "接続詞"), 63 ("INT", "間投詞") 64 ) 65 66 example_sentence = models.ForeignKey("ExampleSentence", on_delete=models.SET_NULL, related_name='english_word', null=True) 67 english_word = models.ForeignKey("EnglishWord", on_delete=models.SET_NULL, related_name='example_sentence', null=True) 68 part_of_speech = models.CharField(max_length=3, choices=PART_OF_SPEECH) 69 japanese_mean = models.CharField(max_length=50) 70 pub_date = models.DateTimeField('date published', default=timezone.now) 71 difficulty = models.IntegerField(default=0) 72 73 def __str__(self): 74 return f"sentence: {self.example_sentence}, english_word: {self.english_word}" 75 76 def was_published_recently(self): 77 now = timezone.now() 78 return now - datetime.timedelta(days=1) <= self.pub_date <= now 79 80 was_published_recently.admin_order_field = 'pub_date' 81 was_published_recently.boolean = True 82 was_published_recently.short_description = 'Published Recently?'

その上で、admin.pyは以下のような形にしました。

python

1# admin.py 2from django.contrib import admin 3 4from .models import EnglishWord, ExampleSentence 5# Register your models here. 6 7class EnglishWordInline(admin.TabularInline): 8 model = ExampleSentence.english_words.through 9 extra = 3 10 11class ExampleSentenceInline(admin.TabularInline): 12 model = ExampleSentence.english_words.through 13 extra = 3 14 15class EnglishWordAdmin(admin.ModelAdmin): 16 fieldsets = [ 17 (None, {'fields': ['spell',]}), 18 ('Date Information', {'fields': ['pub_date']}), 19 ('Word Data', {'fields': ['difficulty']}) 20 ] 21 inlines = [ExampleSentenceInline] 22 list_display = ('spell', 'pub_date', 'difficulty', 'was_published_recently',) 23 list_filter = ['spell', 'pub_date'] 24 search_fields = ['spell'] 25 actions = ['make_english_words_difficulty_zero'] 26 27 def make_english_words_difficulty_zero(self, request, queryset): 28 for english_word in queryset: 29 english_word.difficulty = 0 30 english_word.save() 31 make_english_words_difficulty_zero.short_description = "英語の難易度を0にリセット" 32 33class ExampleSentenceAdmin(admin.ModelAdmin): 34 fieldsets = [ 35 (None, {'fields': ['sentence']}), 36 ('Date Information', {'fields': ['pub_date']}), 37 ('Sentence Data', {'fields': ['difficulty']}) 38 ] 39 inlines = [EnglishWordInline] 40 exclude = ('english_words',) 41 42admin.site.register(ExampleSentence, ExampleSentenceAdmin) 43admin.site.register(EnglishWord, EnglishWordAdmin)

発生している問題・エラーメッセージ

上のソースコードを配置して管理サイトにログインしてExampleSentenceを新規作成しようとすると、以下のような画面になります。

ExampleSentence新規作成

この画面で下部のプラスボタンを押して、makeを「動詞: ~にする」という意味で登録しようとすると、ExampleSentenceが存在しないので登録できないというエラーが返ってきます。

Error

これから作成しようとしているのでExampleSentenceが無いのは当然なのですが、この仕様のままだと「例文を無単語で登録→あらためて開き直して英単語を登録」という作業を行わなければならず、二重登録も頻発します。

例文を新規登録する際に、英単語の方も同時に登録する方法はないでしょうか。あるいは、そもそも実現したいものに対してモデルの構想が適切ではないのでしょうか。

試したこと

null値を許容するようにすればよいのかと考え、models.py内のEnglishWordExampleSentenceクラスを、

python

1example_sentence = models.ForeignKey("ExampleSentence", on_delete=models.CASCADE, related_name='english_word') 2english_word = models.ForeignKey("EnglishWord", on_delete=models.CASCADE, related_name='example_sentence')

から、

python

1example_sentence = models.ForeignKey("ExampleSentence", on_delete=models.SET_NULL, related_name='english_word', null=True) 2english_word = models.ForeignKey("EnglishWord", on_delete=models.SET_NULL, related_name='example_sentence', null=True)

のように変更しましたが、効果はありませんでした。

改善案等をご存知の方は、お手数をおかけしますが、よろしくお願い致します。

2021/07/01追記

それぞれにnull=True, blank=Trueを追加することで、とりあえず存在しない状態でも登録はできるようになりました。ただ、結局二度手間なのは変わっておりません。引き続きご存知の方に対応をお待ちしております。

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

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

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

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問