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

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

ただいまの
回答率

90.51%

  • JavaScript

    20417questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Python 3.x

    9841questions

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

  • Django

    1614questions

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

Djangoのフォームで、選択をフィルタリングする方法

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 1,594

am120sec

score 6

行き詰りました。

最初のプルダウンメニューで選択した項目を
次のプルダウンメニューに連動させたいです。
(admin管理サイトは使用しない)

#model.py

class Create_type(models.Model):
    name = models.CharField(max_length=20,unique=True)
    def __str__(self):
        return self.name

class Genre(models.Model):
    name = models.CharField(max_length=20,unique=True)
    create_type = models.ManyToManyField(Create_type)
    def __str__(self):
        return self.name

class Title_Post(models.Model):
    title = models.CharField(unique=True)
    create_type = models.ForeignKey(Create_type,blank=false)
    genre = models.ManyToManyField(Genre,blank=True)


以下のサイトを参考にForm.pyを作成しました。
https://stackoverflow.com/questions/291945/how-do-i-filter-foreignkey-choices-in-a-django-modelform

#form.py

class Title_Form(forms.ModelForm):
    class Meta:
        model = Title_Post
        fields = ('title','create_type','genre')

    def __init__(self, *args, **kwargs):
        super(Title_Form, self).__init__(*args, **kwargs)
        self.fields['genre'].queryset = Genre.objects.filter(
            type=self.instance.type)
#view.py
def title_new(request):
    if request.method == "POST":
        f = Title_Form(request.POST,request.FILES)
        if f.is_valid():
            post = f.save(commit=False)
            post.published_date = timezone.now()
            post.save()
            f.save_m2m()
            return redirect('app:title', pk=post.pk)
    else:
        f = Title_Form()
    return render(request, 'app/title_edit.html', {'form':f})
小説 映画 アニメ
SF SF SF
ホラー ホラー ホラー
3D 3D

イメージ的には
Type(小説、映画、アニメ)があって、
Genre(SF、ホラー、3D)等のジャンルがあり、
フォーム上で小説を選択した場合、genreのリストでは「3D」を選択できないようにしたいです。
表示しないという動作はJavascriptで記述できたのですが、Javascriptを無効にした場合、不正な入力がされてしまうと思うので、Django側のModelやFormで入力をエラーとしたいです。

現状は、そもそもGenreに値が表示されません・・・

イメージ説明

何卒、よろしくお願いいたします・・

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

とりえあえず、全部選択肢にでるように
formのinitなしにしましょう。

それからTitle_Formのcleanをオーバーライドしましょう
cleanのoverride例
値がおかしかったらValidationErrorをraiseして、
あってたら特に何もしなくていいです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/03/30 13:41

    途中ですが、選択肢は表示されるようになりました。
    次に値の検証ですが、ManyToManyでリレーションされたクラスのフィールドを取得する方法が解りません。
    参考資料でも良いのでヒントを頂けないでしょうか。

    class Title_Form(forms.ModelForm):

    class Meta:
    model = Title_Post
    fields = ('title','create_type','genre')

    def clean(self):
    cleaned_date = super().clean()
    genre = cleaned_date.get("genre")
    create_type = cleaned_date.get("create_type")
    genre_create_type = #ここです

    if genre and create_type:
    if genre.create_type != create_type:
    raise form.balidationError(
    "そのジャンルは使用できません"
    )

    キャンセル

  • 2018/03/31 01:49

    ちょっといま確認できませんけど、
    cleaned_data.get("genre")ってやったらQuerySetが返ってきませんか?
    forで回せるのではないかと。

    キャンセル

  • 2018/04/03 09:02

    その前にcleaned_dataが上手く動いて無いようでした・・
    簡単なcleaned_dataで作ってみてもダメです・・。
    class Title_Form(forms.ModelForm):
    volume = forms.IntegerField(required=False)
    class Meta:
    model = Title_Post
    fields = ('title','create_type','genre','volume')

    def clean_volume(self):
    volume = self.cleaned_date["volume"]
    if not 1 <= volume <= 10:
    raise forms.ValidationError(u"1-10の範囲で入力してください")
    return volume

    これでフォームをSAVEすると、'Title_Form' object has no attribute 'cleaned_date'エラーが出てしまいます。

    view.pyがおかしいのでしょうか・・。

    キャンセル

  • 2018/04/03 19:54 編集

    書くところ間違えました……
    回答は消せないのかな

    "cleaned_data"のタイプミスと思われます。

    キャンセル

  • 2018/04/03 22:53

    私のほうからは削除できませんでした。

    "cleaned_data"でいけました・・・・・・・・・!
    中学生からやり直してきます(´;ω;`)

    キャンセル

  • 2018/04/03 22:58

    スマホからだと見つけられなかったんですが、
    PCで開いたら削除リクエストの場所みつけました。
    お騒がせしました。

    キャンセル

0

やり方が正しいかどうかは置いておいて、とりあえず動く物ができましたので報告です。

genre_filter = genre.filter(create_type__name = create_type)
アンダースコアが2つ入っているのはcreate_typeのnameフィールドを指定するためらしいです。

ご指摘ありましたら是非ともお願いします。

#form.py
class Title_Form(forms.ModelForm):
    volume = forms.IntegerField(required=False)
    class Meta:
        model = Title_Post
        fields = ('title','create_type','genre')


    def clean(self):
        cleaned_date = super().clean()
        genre = self.cleaned_data.get("genre")
        create_type = self.cleaned_data.get("create_type")

        if genre and create_type:
            genre_filter = genre.filter(create_type__name = create_type)
            if len(genre_filter) == 0:
                raise forms.ValidationError(
                    "選択されたジャンルはタイプと関連性がないため使用できません"
                )

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

  • JavaScript

    20417questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Python 3.x

    9841questions

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

  • Django

    1614questions

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