2013-11-04 12 views
17

Ich bin neu in Django Realm, aber sehen Sie, es gibt eine Menge "Magie" dort. Ich verwende Django REST Framework und erstelle eine App, die eine kostenlose Benutzerregistrierung ermöglicht. Mein Benutzer benötigt einige zusätzliche Felder, die in Django-Benutzern nicht verfügbar sind. Also habe ich gegoogelt, um User zu erweitern. Es ist eine Idee, dass dies durch die Schaffung von so etwas wie dieseDjango REST Framework Erstellen benutzerdefinierter Benutzer

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

Das ist in Ordnung, aber ich habe diesen Serializer

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

So ist das Problem, dass diese Serializer ein „magischen“ tun hier . Es versucht herauszufinden, welches Feld sollte Modell haben ... Ich möchte Benutzer mit den hier aufgeführten Felder haben, und diese Felder sind in Benutzer und "Stadt" ist neues benutzerdefiniertes Feld. Der Serializer bekommt nicht, dass er in das Benutzermodell schauen soll.

Was fehlt mir hier? Wie kann ich diesem Serializer mitteilen, dass ich einige Felder in User möchte? Ich muss in der Lage sein, Benutzer auch zu schaffen.

+6

sollten Sie verwenden 'OneToOneField' für Ihre UserModel Beziehung, nicht' ForeignKey' da sie nur ein 'MyUser' für jede' User' Instanz sein. –

+0

Verwenden Sie 'OneToOneField' und folgen Sie dieser Antwort und Sie sind gut zu gehen: [link] (http://Stackoverflow.com/a/28733782/3294412) – musicformellons

Antwort

1

Wenn Sie django 1.5 oder höher verwenden, verwenden Sie stattdessen , damit das Benutzermodell seine eigene dedizierte Tabelle hat und der Serializer die Felder dann korrekt aufnimmt.

+0

Denken Sie, es ist nicht wirklich eine Option, wahrscheinlich werde ich 1.4 verwenden . Ich verstehe nicht wirklich, ist das wirklich schwer zu tun? Warum das? Ich nähere mich wie Standard, warum ist das so kompliziert? – bradojevic

1

Wenn Sie Django Rest Framework verwenden, müssen Sie vorsichtig sein. Jedes benutzerdefinierte Benutzermodell kann die integrierte Tokenauthentifizierung nicht verwenden. Bis Sie das tun können, würde ich vorschlagen, ein OneToOneField mit Benutzer in Ihrem benutzerdefinierten Modell zu verwenden. Ihr benutzerdefiniertes Modell enthält die zusätzlichen Felder, die Sie behalten möchten. One to One gibt Ihnen Zugriff auf den Benutzer von dem benutzerdefinierten Benutzer und dem benutzerdefinierten Benutzer von dem Benutzer.

+5

Es ist fast ein Jahr her, seit du das gepostet hast - unterstützt DRF Djangos Custom User Models noch oder ist diese Antwort immer noch korrekt und OneToOneFields mit Nutzern immer noch die beste Idee? – ArtOfWarfare

12

Okay, ein paar Dinge. Sie möchten eine OneToOneField für Ihre Benutzermodellerweiterung erstellen.

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

nun die Macht des Django Framework-Erholung, ist Sie Ihr Serializer bauen können, von diesen beiden Modellen Daten zu nehmen, wenn die Serialisierung.

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

Schließlich wir Ihre Erstellung der Benutzer, da Sie benutzerdefinierte Felder verwenden, müssen Sie Ihre eigenen restore_object() implementieren, die beiden Modelle aus den Eingangsdaten aufbauen.

Auch das Erstellen von Benutzern in Django ist ein bisschen anders, Sie müssen create_user() anrufen und ein Passwort, das Hashed ist, so ist es nicht so einfach wie Speichern von Feldern aus einem Serialisierer.

+0

Können Sie Ihre Antwort erweitern, um eine Beispielimplementierung von 'restore_object()' und 'create_user()'? Ich bin mir nicht sicher, wie ich mit dem Hashing des Passworts verfahren sollte ... (die Tatsache, dass Sie sogar vorschlagen, dass wir das tun müssen, wirft rote Fahnen in meinen Gedanken auf - sollte Django oder DRF diese Art von Sicherheit nicht bieten die Box?) – ArtOfWarfare

+0

Danke für diese Antwort! Wenn Sie das addieren, können Sie auch das ID-Attribut 'user_profile = serializers.CharField (source = 'userprofile.id')' verwenden. – pasql

16

Also anscheinend habe ich nicht genug Ruf, um einen Kommentar unter einer Antwort zu posten. Aber zu erarbeiten, was Kevin Stein beschrieben, wenn Sie Modell ist das so etwas wie folgt vor:

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

Sie etwas tun können zu schaffen, sowohl die individuelle Benutzer und django Benutzer:

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 restore_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) 
+4

Beachten Sie, dass restore_object() nicht mit DRF 3.x kompatibel ist, sodass Sie stattdessen die Methoden create() und update() verwenden müssen. Beispiel hier: http://www.django-rest-framework.org/topics/3.0-announcement/#serializers. – jarmod

0

Es wäre Sei nett, wenn dieser Anwendungsfall in den Dokumenten leichter zu finden ist. Wie @jamod wies darauf hin, in DRF 3, können Sie es here finden:

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 
1

Ich ziehe das django signals Modul zu verwenden, die Signale an die App sendet, wenn etwas passiert, und unter anderem wird Sie anrufen eine eigene Funktion vor/nach anderen Funktionen.Meine Antwort ähnelt der Antwort von Stuart, behält aber den gesamten für Ihre neue Erweiterungsklasse relevanten Code an einer Stelle (wenn Sie das Profil später löschen oder seinen Namen ändern möchten, müssen Sie nirgendwo anders suchen).

Der folgende Code zeigt Ihr erweitertes Klassenmodell, in diesem Fall ein Benutzerprofil, erstellt dann eine leere Instanz, wenn ein Benutzermodell erstellt wird, speichert dann die Instanz mit neuen Informationen (die Sie selbst hinzufügen müssen) Benutzerinstanz dh Eltern - user.save()

models.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() 

Wenn Sie nicht über einen 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') 

Nachdem Sie Ihren Benutzer erstellt und Ihren Benutzer gespeichert haben, haben Sie ein leeres user.profile, um Informationen hinzuzufügen. Zum Beispiel, nach dem Ausführen python manage.py shell Versuch:

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 
Verwandte Themen