Reputation: 5
I'm creating a staff registration page to create a new user (where NO one has logged in i.e. an Anonymous User). I have a Profile model (adding additional fields such as department, alias etc) which extends from the User model within Django. I've referenced User as a one-to-one relationship to Profile.
When a new staff registers, they have to specify their "stafftypeid" ("Job Title") from the ModelChoiceField referencing Staff_Type table. The User table doesn't store "stafftypeid", so I extended the UserCreationForm.
My problem is that I can successfully submit POST variables via the forms and the User (auth_user) will create a new record. I can see the new User within the Django /admin page. However, Profile will fail to create an accompanying new record and I receive an error ("IntegrityError at /register/ (1048, "Column 'staffTypeID' cannot be null")"). Strangely, I have all the POST variables, but the variables needed for the fields in Profile table are not being passed across.
Is this an inheritance problem? A new Profile record should only be created when you create a new User.
I've tried to follow tutorials and other code from Corey Schafer Django Tutorial 8, Simpleisbetterthancomplex (https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone) and Stack Overflow.
I've also tried re-writing def form.save() and then split my forms into two (originally just one), since its supposed to be easier to handle on the database side. I'd be really grateful for advice here!
Administrator\models.py: (Staff_Type)
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
Upvotes: 0
Views: 238
Reputation: 599450
The error is happening in your signal. There you just create a Profile and only set the user field, you don't set any of the other fields.
You don't need this signal. You are creating the profile in the separate Profile form and saving it in the view. You should remove both those signals.
Then, update the view:
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()
(Separately, please stop naming your ForeignKeys as ending in "_id"; they're not IDs, they are the actual related objects.)
Upvotes: 0