Error de creación de perfil: valor de clave duplicado... user_id ya existe

Estoy creando un sitio con dos tipos de perfiles de usuario (DoctorProfile y PatientProfile). Cada extensión UserProfile, que tiene una relación OneToOneField con User.

Al intentar registrar nuevos usuarios a través de ModelForm, encuentro el siguiente error:

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

Esto parece suceder cuando se crea el perfil del paciente, intenta crear un usuario. Sin embargo, el usuario ya fue creado usando User.objects.create_user()

¿Cómo puedo configurar esto para que pueda crear el usuario solo una vez?

Aquí está mi (reducido) formularios.py:

class PatientProfileForm(ModelForm):
    supplied_email = forms.CharField(max_length=256, label="Email Address", required=True)
    supplied_password = forms.CharField(max_length=256, label="Password", required=True, widget=forms.PasswordInput())
    supplied_password_confirm = forms.CharField(max_length=256, label="Password (again)", required=True, widget=forms.PasswordInput())

    def save(self, profile_callback=None):
        master_patient_profile = MasterPatientProfile(user=User.objects.create_user(username=self.cleaned_data['supplied_email'], email=self.cleaned_data['supplied_email'], password=self.cleaned_data['supplied_password']))
        master_patient_profile.save()

Una versión abreviada de models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User, null=True)
    address_line_1 = models.CharField(_('Address 1'), max_length=100)
    address_line_2 = models.CharField(_('Address 2'), max_length=100, blank=True)
    city = models.CharField(_('City'), max_length=50)
    state = models.CharField(_('State'), max_length=20)
    zipcode = models.CharField(_('ZIP Code'), max_length=5)

class PatientProfile(UserProfile):
    gender = models.ForeignKey(UserGender)
    phone_number = models.CharField(max_length=12)
    date_of_birth = models.DateField(null=True)

class DoctorProfile(UserProfile):
    specialty = models.ManyToManyField(DoctorSpecialty)
    professional_statement = models.TextField()

EDIT: (basado en la sugerencia de Chris Pratt)

Las formas save() El método ahora se ve así:

new_user, created = User.objects.get_or_create(username=self.cleaned_data['supplied_email'], email=self.cleaned_data['supplied_email'])
    if created:
        new_user.set_password(self.cleaned_data['supplied_password'])

    master_patient_profile = MasterPatientProfile(user=new_user)

preguntado el 12 de junio de 12 a las 15:06

1 Respuestas

No use create_user. Eso es puramente un método de conveniencia y solo es realmente útil para el real User forma de creación.

En cualquier otro lugar, deberías estar usando get_or_create. El único inconveniente es que no puede configurar la contraseña con eso, por lo que debe hacerlo en dos pasos.

user, created = User.objects.get_or_create(username=self.cleaned_data['supplied_email'], email=self.cleaned_data['supplied_email'])
if created:
    user.set_password(self.cleaned_data['supplied_password'])

Respondido el 12 de junio de 12 a las 16:06

Gracias por el consejo. lo he incorporado. Sin embargo, dado que el usuario todavía es creado por get_or_create(), y el perfil todavía parece estar intentando crear el usuario también, sigo recibiendo el error de clave duplicada. ¿Conoces una forma de evitar eso? - Jorge Cummins

El usuario solo obtendrá crear por get_or_create si los valores proporcionados, username y email no coincide con nada en la base de datos. Creo que tu problema está en otra parte. ¿Tiene alguna señal que esté vinculada a User o alguno de sus modelos aquí? - Chris Pratt

Este es un nuevo formulario de registro de usuario, así que espero username y email que no coincida con nada y que se cree un nuevo usuario. Tenías razón sobre la señal: tenía post_save.connect(create_user_profile, sender=User) en models.py, y create_user_profile estaba creando la segunda instancia. ¡Gracias por la ayuda! - Jorge Cummins

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.