Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django user creation fails in the admin when filling profile fields

I'm using Django 1.4.1 with postgresql 9.1.

I need to add a profile to the User given with the auth app, and to allow the admin app to create and edit this profile. Thus I've been following the docs section Storing additional information about users :

models.py

class UserProfile(models.Model):
    user = models.OneToOneField(User)

    bio = models.TextField(null = True, blank = True)
    contact = models.TextField(null = True, blank = True)

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

post_save.connect(create_user_profile, sender=User)

settings.py

...
AUTH_PROFILE_MODULE = 'userprofile.UserProfile'
...

I also activated the django.contrib.auth and django.contrib.admin apps in INSTALLED_APPS.

admin.py

class UserProfileInline(admin.StackedInline):
    model = UserProfile
    can_delete = False
    verbose_name_plural = 'profile'

class UserAdmin(UserAdmin):
    inlines = (UserProfileInline, )

# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

Problem

Now, when I run the admin app and ask to add (create) a new user, I'm asked to create my user through a two-step process : first, a page asking for only the username, password (twice), and my two UserProfile fields.

If I type only the username and the password (twice) and click "Save", I'm showed the second page of the process, which allows to fill in all the other User fields, as well as my UserProfile fields. There's a message saying "The user "xxxxx" was added successfully. You may edit it again below.", and fortunately I can edit fields from both models, it works.

But if I try to type anything into one or both of my UserProfile fields in the first page, the submit fails with the message :

IntegrityError at /admin/auth/user/add/

duplicate key value violates unique constraint "userprofile_userprofile_user_id_key"
DETAIL:  Key (user_id)=(7) already exists.

The "7" is incremented each time I try.

How can that behavior be avoided, or alternatively how can I prevent the profile fields to be editable in the first page, but letting them be edited in the second page ?

Full traceback :

Environment:

Request Method: POST
Request URL: http://127.0.0.1:8000/admin/auth/user/add/

Django Version: 1.4.1
Python Version: 2.7.3
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'django.contrib.admindocs',
 'userprofile')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')

Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in wrapper
  366.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/cache.py" in _wrapped_view_func
  89.         response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/sites.py" in inner
  196.             return view(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/debug.py" in sensitive_post_parameters_wrapper
  69.             return view(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapper
  25.             return bound_func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in bound_func
  21.                 return func(self, *args2, **kwargs2)
File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py" in inner
  209.                 return func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/auth/admin.py" in add_view
  114.                                                extra_context)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapper
  25.             return bound_func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view
  91.                     response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in bound_func
  21.                 return func(self, *args2, **kwargs2)
File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py" in inner
  209.                 return func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in add_view
  956.                 self.save_related(request, form, formsets, False)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in save_related
  733.             self.save_formset(request, form, formset, change=change)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in save_formset
  721.         formset.save()
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in save
  497.         return self.save_existing_objects(commit) + self.save_new_objects(commit)
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in save_new_objects
  628.             self.new_objects.append(self.save_new(form, commit=commit))
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in save_new
  731.             obj.save()
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py" in save
  463.         self.save_base(using=using, force_insert=force_insert, force_update=force_update)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py" in save_base
  551.                 result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py" in _insert
  203.         return insert_query(self.model, objs, fields, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py" in insert_query
  1576.     return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py" in execute_sql
  910.             cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/util.py" in execute
  40.             return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/postgresql_psycopg2/base.py" in execute
  52.             return self.cursor.execute(query, args)

Exception Type: IntegrityError at /admin/auth/user/add/
Exception Value: duplicate key value violates unique constraint "userprofile_userprofile_user_id_key"
DETAIL:  Key (user_id)=(7) already exists.`
like image 235
Manur Avatar asked Dec 27 '22 16:12

Manur


1 Answers

As CadentOrange mentioned in a comment, the solution to this problem is described in this answer.

The problem is with using an inline admin form. Here's what happens:

  1. It saves the main model (User)
  2. Due to (1), The post_save signal handler for User is fired, which creates a new UserProfile object
  3. Each inline model is saved (including another copy of your UserProfile, resulting in the dupe).
like image 126
mgalgs Avatar answered Dec 29 '22 12:12

mgalgs