@chaya

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Django Form.is_valid()が常にFalseとなる。

アプリケーションの構成

/LedgerEmployee/
/LedgerStation/

 施設(Station)、看護師(Employee)のモデルがあり、看護師は複数の施設に所属するため、施設とは多対多の関係にあります(ManyToManyField: belong_to)。

【症状】

看護師の新規登録フォームのPOST時に、バリデーションが常にFalseとなる。

【補足】

看護師の新規登録フォームは、belong_to設置前までは正常に登録できていた(True)ため、おそらく多対多に関わるミスではないかと考えています。
(設置後でも/adminページでは正しく登録できましたが、他の人には/adminに入れさせたくない)

当方、非IT業種のため、コードが読みづらいと思います。
長々してしまうため、関係がありそうなファイルのみ載せてみました。
ご助言お願いします。

/LedgerEmployee/models.py

from django.db import models

# Create your models here.
from django.conf import settings
from LedgerStation.models import Station  # 施設台帳

class Employee(models.Model):
    name_kanji = models.CharField('氏名(漢字)', max_length=20)
    name_kana = models.CharField('氏名(かな)', max_length=20)
    tel1 = models.CharField('電話番号1', max_length=13)
    tel2 = models.CharField('電話番号2', max_length=13, default='', blank=True)
    postal_code = models.CharField('郵便番号', max_length=8, default='', blank=True)
    address = models.TextField('住所', default='', blank=True)
    email = models.CharField('email', max_length=30, default='', blank=True)
    nurse_licence_type = models.CharField('看護師免許種別', max_length=4, \
        choices=settings.NURSE_LICENCE_TYPE, default='なし')
    nurse_licence_num = models.CharField('看護師免許番号', max_length=10, default='', blank=True)
    nurse_licence_date = models.CharField('看護師免許取得日', max_length=10, default='', blank=True)
    belong_to = models.ManyToManyField(Station, verbose_name='所属', blank=True)  # 施設台帳とのリレーション。
    memo = models.TextField('メモ', default='', blank=True)  # TextField … 制限なし

    created_at = models.DateTimeField('登録日時', auto_now_add=True, editable=True)
    created_by = models.CharField('登録者', max_length=20, default='', blank=True)
    updated_at = models.DateTimeField('更新日時', auto_now=True, editable=True)
    updated_by = models.CharField('最終編集者', max_length=20, default='', blank=True)

    class Meta:
        db_table = 'T_Employees'

    def __str__(self):
        return f'{self.pk}{self.name_kanji}'

/LedgerEmployee/views.py

def le_new(request):  # データ登録用のview
    form = EmployeeForm(request.POST)
    if form.is_valid():  # False のため、そもそもこの分岐には入らない。
        employee = form.save(commit=False)
        employee.created_by = str(request.user.last_name) + ' ' + str(request.user.first_name)  # 管理画面より参照。
        employee.save()
        return redirect(le_detail, employee_id=employee.pk)
    else:  # GET時とバリデーションFalse時にデータ登録画面のFormを表示するため、POSTしても全てここを辿る。
        context = {'form': form, 'navigation': '社員台帳: 新規登録'}
        return render(request, 'LedgerEmployee/le_new.html', context)

/LedgerEmployee/forms.py

from django import forms
from LedgerEmployee.models import Employee

class EmployeeForm(forms.ModelForm):
    class Meta:
        model = Employee
        # fields = ['name_kanji', 'name_kana', 'tel1', 'tel2', 'postal_code', 'address', 'email', 'nurse_licence_type', 'nurse_licence_type', 'nurse_licence_num', 'nurse_licence_date', 'belong_to', 'memo',]
        fields = '__all__'
        exclude = ('belong_to', 'created_at', 'created_by', 'updated_at', 'updated_by', )  # 除外フィールド最後にカンマ。

/templates/LedgerEmployee/le_new.html

{% extends 'base.html' %}
{% block main %}
<form method='post mt-1'>
        {% csrf_token %}
        {{ form.as_p }}
        <button class='btn btn-primary' type='submit'>登録</button>
        <a class='btn btn-primary' href='{% url "le_top" %}'>戻る</a>
    </form>
{% endblock %}

/LedgerStation/models.py

from django.db import models

# Create your models here.
from django.conf import settings

class Station(models.Model):
    name_kanji = models.CharField('施設名(漢字)', max_length=50, default='')
    name_kana = models.CharField('施設名(かな)', max_length=50, default='')
    postal_code = models.CharField('郵便番号', max_length=8)
    address = models.TextField('住所')
    tel1 = models.CharField('電話番号1', max_length=13)
    tel2 = models.CharField('電話番号2', max_length=13, blank=True, default='')
    fax = models.CharField('Fax番号', max_length=13, blank=True, default='')
    memo = models.TextField('メモ', default='', blank=True)

    created_at = models.DateTimeField('登録日時', auto_now_add=True, editable=True)
    created_by = models.CharField('登録者', max_length=20, default='', blank=True)
    updated_at = models.DateTimeField('更新日時', auto_now=True, editable=True)
    updated_by = models.CharField('最終編集者', max_length=20, default='', blank=True)

    class Meta:
        db_table = 'T_Stations'

    def __str__(self):
        return self.name_kanji

Log的なアレ

(0.004) SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_date" FROM "django_session" WHERE ("django_session"."expire_date" > '2021-10-08 13:54:47.332823' AND "django_session"."session_key" = 'guvgg58fs7b57ai9yik9t9moswbrldp9') LIMIT 21; args=('2021-10-08 13:54:47.332823', 'guvgg58fs7b57ai9yik9t9moswbrldp9')
(0.001) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1 LIMIT 21; args=(1,)
[08/Oct/2021 22:43:34] "GET /LedgerEmployee/new/?csrfmiddlewaretoken=I7fFEpDGYJ9c8fJl6Z5ezk2lGqWNCvSss0eJm4wEHjWkQDuw2pjjwAPpLPQufrKI&name_kanji=test1&name_kana=test2&tel1=test&tel2=&postal_code=&address=&email=&nurse_licence_type=%E3%81%AA%E3%81%97&nurse_licence_num=&nurse_licence_date=&memo= HTTP/1.1" 200 3733
0 likes

1Answer

まずは、何のvalidateでエラーが起きているか確認するのが良いかと思います

/LedgerEmployee/views.py
def le_new(request):  # データ登録用のview
    form = EmployeeForm(request.POST)
    if form.is_valid():  # False のため、そもそもこの分岐には入らない。
        employee = form.save(commit=False)
        employee.created_by = str(request.user.last_name) + ' ' + str(request.user.first_name)  # 管理画面より参照。
        employee.save()
        return redirect(le_detail, employee_id=employee.pk)
    else:  # GET時とバリデーションFalse時にデータ登録画面のFormを表示するため、POSTしても全てここを辿る。
        # デバッグ目的で、エラーの内容をコンソール出力する
        print(form.errors)

        context = {'form': form, 'navigation': '社員台帳: 新規登録'}
        return render(request, 'LedgerEmployee/le_new.html', context)
0Like

Your answer might help someone💌