Django REST Framework Creación de usuario personalizado

Soy nuevo en el reino de Django pero veo que hay mucha “magia” ahí. Estoy usando Django REST Framework y creando una aplicación que permitirá el registro gratuito de usuarios. Mi usuario necesita algunos campos adicionales que no están disponibles en el usuario de Django. Así que busqué en Google para extender el usuario. Hay una idea de que esto debería hacerse creando algo como esto.

class MyUser(models.Model): user = models.ForeignKey(User, unique=True) city = models.CharField(max_length=50, blank=True, default='') 

Esto está bien pero tengo este serializador

 class UserSerializer(serializers.ModelSerializer): class Meta: model = MyUser fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'city') 

Entonces, el problema es que este serializador hace algo de “magia” aquí. Intenta averiguar qué campo debería tener el modelo … Quiero que el usuario tenga los campos que se enumeran aquí, y estos campos están en Usuario y “ciudad” es un nuevo campo personalizado. Serializador no consigue que se vea dentro del modelo de usuario.

¿Que me estoy perdiendo aqui? ¿Cómo decirle a este serializador que quiero algunos campos dentro de Usuario? Necesito ser capaz de crear usuarios también.

Así que aparentemente no tengo suficiente reputación para publicar un comentario debajo de una respuesta. Pero para elaborar sobre lo que describió Kevin Stone, si modelas es algo como lo siguiente:

 class AppUser(models.Model): user = models.OneToOneField(User) ban_status = models.BooleanField(default=False) 

Puedes hacer algo como esto para crear tanto el usuario personalizado como el usuario de django:

 class AppUserSerializer(serializers.ModelSerializer): username = serializers.CharField(source='user.username') email = serializers.CharField(source='user.email') password = serializers.CharField(source='user.password') ban_status = serializers.Field(source='ban_status') class Meta: model = AppUser fields = ('id', 'username', 'email', 'password', 'ban_status') def restre_object(self, attrs, instance=None): """ Given a dictionary of deserialized field values, either update an existing model instance, or create a new model instance. """ if instance is not None: instance.user.email = attrs.get('user.email', instance.user.email) instance.ban_status = attrs.get('ban_status', instance.ban_status) instance.user.password = attrs.get('user.password', instance.user.password) return instance user = User.objects.create_user(username=attrs.get('user.username'), email= attrs.get('user.email'), password=attrs.get('user.password')) return AppUser(user=user) 

Vale, un par de cosas. Desea crear un OneToOneField para su extensión de modelo de usuario.

 class MyUser(models.Model): user = models.OneToOneField(User) city = models.CharField(max_length=50, blank=True, default='') 

Ahora, el poder de Django Rest Framework es que puede construir su serializador, para tomar datos de ambos modelos cuando se serializa.

 class UserSerializer(serializers.ModelSerializer): city = serializers.CharField(source='myuser.city') class Meta: model = User fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'city') 

Finalmente, donde está creando el usuario, ya que está usando campos personalizados, necesita implementar su propio restre_object() que construye ambos modelos a partir de los datos de entrada.

Además, la creación de Usuarios en Django es un poco diferente, debe llamar a create_user() y proporcionar una contraseña con hash, por lo que no es tan simple como almacenar campos desde un serializador.

Si está utilizando django 1.5 o superior, en su lugar use un modelo de usuario personalizado , de esta manera, el modelo de usuario tendrá su propia tabla dedicada y el serializador recogerá los campos correctamente.

Al usar Django Rest Framework tienes que tener cuidado. Cualquier modelo de usuario personalizado no puede utilizar la autenticación de token integrada. Hasta que pueda hacer eso, sugeriría usar un OneToOneField con un usuario en su modelo personalizado. Su modelo personalizado contendrá los campos adicionales que desea conservar. One to One le da acceso al usuario del usuario personalizado y al usuario personalizado del usuario.

Sería bueno si este caso de uso fuera más fácil de encontrar en los documentos. Como @jamod señaló, en DRF 3, puede encontrarlo aquí :

 class UserSerializer(serializers.ModelSerializer): profile = ProfileSerializer() class Meta: model = User fields = ('username', 'email', 'profile') def create(self, validated_data): profile_data = validated_data.pop('profile') user = User.objects.create(**validated_data) Profile.objects.create(user=user, **profile_data) return user 

Prefiero usar el módulo de señales django, que envía señales a la aplicación cuando ocurre algo y, entre otras cosas, le permitirá llamar a una función propia antes / después de otras funciones. Mi respuesta es similar a la de Stuart, pero mantiene todo el código relevante para su nueva clase de extensión en un lugar (si desea eliminar el perfil más tarde o cambiar su nombre, no tiene que buscar en ningún otro lugar).

El siguiente código establece su modelo de clase extendida, en este caso un perfil de usuario, luego crea una instancia vacía cuando se crea un modelo de usuario, luego guarda la instancia con nueva información (que debe agregar usted mismo) guardando la instancia de usuario principal, es decir – user.save()

modelos.py

 from django.db.models.signals import post_save from django.db import models from django.contrib.auth.models import User class Profile(models.Model): #This extends the user class to add profile information user = models.OneToOneField(User, on_delete=models.CASCADE) #add your extra traits here: is_nice, is_shwifty, address, etc. is_nice = models.BooleanField(default=True, blank=True) # a user model was just created! This now creates your extended user (a profile): @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: # instance is the user model being saved. Profile.objects.create(user=instance) # a user model was just saved! This now saves your extended user (a profile): @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): instance.profile.save() 

Si no tiene un ProfileSerializer: serializers.py

 #use hyperlinkedmodelserializer for easy api browsing + clicking class ProfileSerializer(serializers.HyperlinkedModelSerializer): user = UserSerializer() class Meta: model = Profile fields = ('url', 'user', 'is_nice') 

Después de crear su usuario y guardarlo, tendrá un perfil de usuario vacío para agregar información. Por ejemplo, después de ejecutar python manage.py shell intente:

 from backend.models import User, Profile #create your user user=User(username="GravyBoat") user.save() #now update your user's profile user.profile.is_nice=False #that's one mean gravy boat user.save() user.profile.is_nice #False