0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DjangoのManyToManyフィールドをCharFieldで入力する

Posted at

前置き

恐らくこの記事を見ている方は僕と同じ「ManyToManyFieldを直接formで使いたい」と思っている方でしょう。
そんな方に向けてどう対処するかを自分なりにまとめてみました。

ManyToManyFieldを直接formで使うとどうなる?

その前に、まずはモデル構造から見ていきましょう。
今回は記事とタグの多対多での関係になります。

models.py
タグモデル
class Tag(models.Model):
    slug = models.CharField(verbose_name='SLUG', unique=True, max_length=20, primary_key=True)
    name = models.CharField(verbose_name='タグ名', unique=True, max_length=20)
    created_at = models.DateTimeField(verbose_name='作成日時', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新日時', auto_now=True)

記事モデル
class Article(models.Model):
    title = models.CharField(verbose_name='タイトル', default='タイトルです。', max_length=30, null=False, blank=False)
    text = models.TextField(verbose_name='テキスト', default='テキストです。', max_length=255, null=False, blank=False)
    author = models.ForeignKey(get_user_model(), verbose_name='作成者', on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag, verbose_name='タグ', related_name='articles')
    created_at = models.DateTimeField(verbose_name='作成日時', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新日時', auto_now=True)

記事モデルとタグモデルは多対多の関係なので、中間テーブルを作成する必要があります。
ですが、DjangoではManyToManyFieldを使うと自動で中間テーブルを作成してくれます。なんと便利なんでしょうか。

で、そのままManyToManyFieldを使ってみました。

forms.py
class ArticleNewForm(forms.ModelForm):

    class Meta:
        model = Article
        fields = {
            'title',
            'text',
            'tags, #tagsがManyToManyFieldに設定したもの
        }

こうするとどうなるかと言うと、

ManyToManyFieldを定義したとき、それをそのまま継承してModelFormを作成するとModelChoiceFieldが設定されます

なので、formのエラー(errors)を吐かせるとこんな感じで怒られます。

正しく選択してください。 〇〇は候補にありません。

じゃあどうするかって言うと、もうやけくそになってCharFieldを作ってしまえ!!って感じですね。笑

CharFieldの作成

先ほどのforms.pyにforms.CharFieldを作成していきます。

修正したforms.py
class ArticleNewForm(forms.ModelForm):
    # 追加
    tags = forms.CharField(label="タグ", max_length=〇〇)

    class Meta:
        model = Article
        fields = {
            'title',
            'text',
            'tags, #こいつは消す
        }

こうすることでcleaned_data['tags']で入力した値を取得できます。
あとはいつも通りに使えば解決ですね。

まとめ(タグの場合)

・ManyToManyFieldをそのままModelFormのfieldsに書き込むとModelChoiceFieldが設定される

・forms.CharFieldにて新たにtagsを定義し、feildsの中のtagsを消す

・forms.CharFieldのデータをcleaned_data['tags']で取得する

参考記事

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?