I really confised, because problem sounds trivial, but I didn’t googled anything related to this. I found one very simular question Django Admin Create Form Inline OneToOne but in my case I cannot remove signal, it’ll break normal way of user creation in my app.
I have model User and Profile connected OneToOne relationship (models.py):
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from .managers import UserManager
class User(AbstractUser):
"""auth/login-related fields"""
username = None
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
class Profile(models.Model):
"""profile fields"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
about = models.CharField(max_length=2000, blank=True)
telegram = models.CharField(max_length=25, blank=True)
def save(self, *args, **kwargs):
print('save profile', args, kwargs) # from admin it run 2 times, second with empty args, kwargs so PROBLEM HERE!!!
print('save profile complete')
"""receivers to add a Profile for newly created users"""
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
print('create_user_profile', created, instance.id)
if created:
try:
p = Profile.objects.create(user = instance)
print('succsecc!!!!', p, p.id) ## here profile object created and got id
except Exception as e:
print('create profile error', e) # never prints
else:
instance.profile.save()
""" @receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
print('save_user_profile')
try:
instance.profile.save()
except Exception:
print('save profile error', Exception)
"""
This models works well from frontend of my application, users register and fill their profiles, everything OK.
Problem occur when I try to make user from django admin. Then I getting django.db.utils.IntegrityError: UNIQUE constraint failed: authenticate_profile.user_id.
My admin.py file looks like this:
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, ReadOnlyPasswordHashField
from django import forms
from django.contrib.auth import get_user_model
from .models import Profile
from .forms import SignUpForm
User = get_user_model()
class UserInline(admin.StackedInline):
model = Profile
can_delete = True
verbose_name = Profile
def save_model(self, request, obj, form, change):
print('save_model profile', request.POST, obj, form, change) ## never prints
super().save_model(request, obj, form, change)
class CustomUserAdmin(UserAdmin):
add_form = SignUpForm
form = UserChangeForm
model = User
list_display = ('email', 'first_name', 'last_name', 'is_staff', 'is_active',)
list_filter = ('email', 'first_name', 'last_name', 'is_staff', 'is_active',)
fieldsets = (
(None, {'fields': ('email', 'first_name', 'last_name' 'password1', 'password2')}),
('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'first_name', 'last_name', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
inlines = (UserInline, )
def save_model(self, request, obj, form, change):
print('save_model user', request.POST, obj, form, change)
super().save_model(request, obj, form, change)
admin.site.register(User, CustomUserAdmin)
Code in post_save signal successfully runs, and creates profile, after that django tries to save profile from inlined form, and fails with this error django.db.utils.IntegrityError: UNIQUE constraint failed authenticate_profile.user_id
. From logs I see, Profile.save(), when I create user from admin, called twice, second time without args and kwargs. But when I override save method of profile model, not to run super().save()
without arguments, I have no errors, but I unable to save profile both from admin and frontend. So problem lies in this method – HOW TO OVERRIDE IT TO WORK BOTH FROM ADMIN AND NORMAL WORKFLOW?. Thanks in advance!
3
Answers
That was tricky… I think you forgot quotes around verbose_name. should be
the email field unique will give you problems I advise using
I had the same problem and found a workaound. I divided the data entry into two steps.
In the administration, I first create only the
User
object and theProfile
object is created using the signal. Only when both objects are created, I also displayUserInline
(nameProfileInline
would be more accurate).