从ModelForm(Django中扩展的用户模型)提交POST变量后,发生完整性错误

时间:2019-04-01 15:34:59

标签: django django-models django-forms

我正在创建一个员工注册页面以创建一个新用户(没有人登录过,即匿名用户)。我有一个Profile模型(添加了其他字段,例如Department,alias等),它是Django中User模型的扩展。我已将User视为与Profile的一对一关系。

新职员注册时,他们必须从ModelChoiceField引用Staff_Type表中指定其“ stafftypeid”(“职位”)。 User表不存储“ stafftypeid”,因此我扩展了UserCreationForm。

我的问题是我可以通过表单成功提交POST变量,并且用户(auth_user)将创建新记录。我可以在Django / admin页面中看到新用户。但是,个人档案将无法创建伴随的新记录,并且我收到一条错误消息(“ / register / (1048,“列'staffTypeID'不能为空”))。奇怪的是,我拥有所有POST变量,但没有传递Profile表中字段所需的变量。

这是继承问题吗?仅当您创建新用户时,才创建新的配置文件记录。

我尝试遵循Corey Schafer Django教程8,Simpleisbetterthancomplex(https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone)和Stack Overflow中的教程和其他代码。

我还尝试过重新编写 def form.save(),然后将我的表单分成两个(最初只是一个),因为它在数据库方面更容易处理。我真的很感谢这里的建议!

Administrator \ models.py :(员工类型)

from django.db import models
from decimal import Decimal

class Staff_Type(models.Model):
    stafftypeid = models.AutoField(db_column='staffTypeID', primary_key=True)  
    stafftypedesc = models.CharField(db_column='staffTypeDesc', max_length=150)

    class Meta:
        ordering = ['stafftypedesc']
        unique_together = ('stafftypedesc',)
        db_table = 'stafftype'

    def __str__(self):
        return self.stafftypedesc

Users \ models.py:

from django.db import models
from django.contrib.auth.models import User
from decimal import Decimal


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    stafftypeid = models.ForeignKey('Administrator.Staff_Type', models.DO_NOTHING, db_column='staffTypeID')
    employeeid = models.CharField(max_length=20)
    alias = models.CharField(max_length=20)
    department = models.CharField(max_length=150)
    organization = models.CharField(max_length=150)
    fte = models.DecimalField(max_digits=4, decimal_places=1, default=Decimal(100.0))


    def __str__(self):
        return f'{self.user.username} Profile'

Users \ signals.py:

from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile


@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
    instance.profile.save()

Users \ register.html:

{% extends "Administrator/adminBase.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-md-8">
    <div class="content-section">
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Register New User </legend>
                {{ user_form|crispy }}
                {{ profile_form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Sign Up</button>
            </div>
        </form>
    </div>
</div>
{% endblock content %}

Users \ forms.py:


from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from Administrator.models import Staff_Type
from .models import Profile

from .models import Profile
from django.utils.translation import ugettext_lazy as _


class UserRegisterForm(UserCreationForm):
    email = forms.EmailField(max_length=150, label = "Email")
    first_name = forms.CharField(max_length=150, label = "First Name")
    last_name = forms.CharField(max_length=150, label = "Surname")

    class Meta:
        model = User
        fields = ['username', 'email', 'first_name', 'last_name', 'password1', 'password2']


class ProfileForm(forms.ModelForm):
    stafftypeid = forms.ModelChoiceField(queryset=Staff_Type.objects.all(), empty_label="Staff Type")
    employeeid = forms.CharField(max_length=20, label="Employee ID")
    alias = forms.CharField(max_length=20, label="Alias")
    department = forms.CharField(max_length=150, label="Department")
    organization = forms.CharField(max_length=150, label="Organization")
    fte = forms.DecimalField(max_digits=4, decimal_places=1, min_value=0.0, max_value=100.0, label="FTE(%)")

    class Meta:
        model = Profile
        fields = ['stafftypeid', 'employeeid', 'alias', 'department', 'organization', 'fte']


Users \ views.py:

from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm, ProfileForm


def register(request):
    if request.method == "POST":
        user_form = UserRegisterForm(request.POST)
        profile_form = ProfileForm(request.POST)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            username = user_form.cleaned_data.get('username')
            stafftypeid = profile_form.cleaned_data.get('stafftypeid')
            messages.success(request, f'Account created for {username}, with alias: {stafftypeid}')
            return redirect('admin-home')
    else:
        user_form = UserRegisterForm()
        profile_form = ProfileForm()
    return render(request, 'users/register.html', {'user_form': user_form, 'profile_form': profile_form})

Users \ apps.py:

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'

    def ready(self):
        import users.signals

1 个答案:

答案 0 :(得分:0)

您的信号中出现错误。在那里,您只需创建一个配置文件,并仅设置用户字段,而无需设置其他任何字段。

您不需要此信号。您将在单独的“个人档案”表单中创建个人档案,并将其保存在视图中。您应该删除这两个信号。

然后,更新视图:

    if user_form.is_valid() and profile_form.is_valid():
        user = user_form.save()
        profile = profile_form.save(commit=False)
        profile.user = user
        profile.save()

(另外,请不要再将外键命名为以“ _id”结尾;它们不是ID,而是实际的相关对象。)