DjangoのModelChoiceFieldの初期値を設定する方法

DjangoのModelChoiceFieldの初期値を設定する方法をご紹介します。

ここでは、プルダウンリストで初期値を設定する方法を例にとります。

条件

  • Django 2.1.7
  • Python 3.7.0

実装

models.py

以下のようなモデルを考えます。
投稿者:投稿 = 1:N になるものとします。

from django.db import models
from django.urls import reverse
from django.contrib.auth.models import AbstractUser


class CustomUser(AbstractUser):

    def __str__(self):
        return self.username + ":" + self.email


class Post(models.Model):
    """投稿モデル"""
    class Meta:
        db_table = 'post'

    title = models.CharField(verbose_name='タイトル', max_length=255)
    text = models.CharField(verbose_name='内容', max_length=255, default='', blank=True)
    author = models.ForeignKey(
        'search.CustomUser',
        on_delete=models.CASCADE,
    )
    created_at = models.DateTimeField(verbose_name='登録日時', auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name='更新日時', auto_now=True)

    def __str__(self):
        return self.title + ',' + self.text

    @staticmethod
    def get_absolute_url(self):
        return reverse('search:index')

urls.py

検索画面、登録画面、詳細画面を用意します。
本記事で主に使用するのは「登録画面」です。

# urls.py

from django.urls import path
from . import views

app_name = 'search'

urlpatterns = [
    # 検索画面
    path('', views.IndexView.as_view(), name='index'),

    # 登録画面
    path('create/', views.CreateView.as_view(), name='create'),
    
    # 詳細画面
    path('search/<int:pk>/', views.DetailView.as_view(), name='detail'),

forms.py

登録画面用のフォームを定義します。

# forms.py抜粋

from .models import Post
from django import forms

class PostForm(forms.ModelForm):

    class Meta:
        model = Post
        fields = ('title','text','author',)

views.py

以下はviews.pyの抜粋です。
ポイントはCreateViewクラスのget_form_kwargs()において、フォームに初期値を設定していることです。

# views.py抜粋

from django.views import generic
from .models import Post
from .forms import PostForm
from django.shortcuts import reverse

class CreateView(generic.CreateView):
    # 登録画面
    model = Post
    form_class = PostForm

    def get_success_url(self):  # 詳細画面にリダイレクトする。
        return reverse('search:detail', kwargs={'pk': self.kwargs['pk']})

    def get_form_kwargs(self, *args, **kwargs):
        form_kwargs = super().get_form_kwargs(*args, **kwargs)
        form_kwargs['initial'] = {'author': self.request.user}  # フォームに初期値を設定する。
        return form_kwargs


class DetailView(generic.DetailView):
    # 詳細画面
    model = Post
    template_name = 'search/detail.html'

template

post_form.html

登録画面用のテンプレートです。

{% extends 'base.html' %}
{% load i18n static %}

{% block content %}
    <div class="col-lg-6 offset-lg-3">

    <h1>Registration</h1>

    <form method="post" enctype="multipart/form-data">

        {% csrf_token %}

        {% if form.errors %}
            <p class="error-msg">
            {% if form.errors.items|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
            </p>
        {% endif %}

        {{ form.title.errors }}
        <div class="form-group form-inline">
            <label class="col-offset-1 col-3 control-label">
                {{ form.title.label_tag }}
            </label>
            <div class="">
                {{ form.title }}
            </div>
        </div>

        {{ form.text.errors }}
        <div class="form-group form-inline">
            <label class="col-offset-1 col-3 control-label">
                {{ form.text.label_tag }}
            </label>
            <div class="">
                {{ form.text }}
            </div>
        </div>

        {% if user.is_superuser %}
            {{ form.author.errors }}
            <div class="form-group form-inline">
                <label class="col-offset-1 col-3 control-label">
                    {{ form.author.label_tag }}
                </label>
                <div class="">
                    {{ form.author }}
                </div>
            </div>
        {% endif %}

        <div class="btn-toolbar justify-content-center" role="toolbar" aria-label="ボタングループのツールバー">
            <div class="btn-group mr-2">
                <a class="btn btn-primary w-150px" href="{% url 'search:index' %}" role="button">検索画面へ</a>
            </div>
            <div class="btn-group mr-2">
                <input class="btn btn-success w-150px" type="submit" id="button" name="button" value="登録実行">
            </div>
        </div>

    </form>

    </div>
{% endblock %}

detail.html

詳細画面用のテンプレートです。

{% extends 'base.html' %}

{% block content %}
<div class="col-lg-6 offset-lg-3">

    <h1>Detail</h1>

    {% if messages %}
    <ul class="messages">
        {% for message in messages %}
            <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
                <h2 class="info-msg">{{ message }}</h2>
            </li>
        {% endfor %}
    </ul>
    {% endif %}

    <table class="table table-hover table-bordered">
        <tbody>
            <tr>
                <th width="40%">タイトル</th>
                <td width="60%">{{ post.title }}</td>
            </tr>
            <tr>
                <th width="40%">内容</th>
                <td width="60%">{{ post.text }}</td>
            </tr>
        </tbody>
    </table>


    <div class="btn-toolbar justify-content-center" role="toolbar" aria-label="ボタングループのツールバー">
        <div class="btn-group mr-2">
            <a class="btn btn-primary w-150px" href="{% url 'search:index' %}" role="button">検索画面へ</a>
        </div>
    </div>

</div>
{% endblock %}

実行結果

フォームに初期値を渡さない場合

Autherのプルダウンリストが、未選択の状態で表示されます。

フォームに初期値を渡す場合

Autherのプルダウンリストが、初期値で渡した「ログインユーザー」が選択された状態で表示されます。

サンプルソース

GitHubに当該記事のサンプルソースを公開しています。

https://github.com/kzmrt/list

参考

Django公式:Passing custom parameters to formset forms

https://docs.djangoproject.com/ja/2.1/topics/forms/formsets/#passing-custom-parameters-to-formset-forms

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です