2013-11-04 45 views
17

我是Django领域的新手,但看到这里有很多“魔术”。我正在使用Django REST Framework并创建允许免费用户注册的应用程序。我的用户需要一些Django用户不可用的附加字段。所以我google扩展用户。有一个想法,这应该通过建立这样的事情Django REST框架创建自定义用户

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

这是不错,但我有这个串行

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

那么做,问题是,这串做一些“神奇”在这里。它试图找出应该模型有哪些字段... 我想让用户在这里列出的字段,这些字段是在用户和'城市'是新的自定义字段。序列化程序没有得到它应该看用户模型。

缺少什么我在这里?如何告诉这个序列化程序,我想在用户内部的一些字段?我需要能够克里特用户。

+6

你应该使用'OneToOneField'您的usermodel关系,而不是'ForeignKey',因为它们可以为每个'User'实例只能有一个'MyUser'。 –

+0

使用'OneToOneField'并按照这个答案,你很好去:[链接](http://stackoverflow.com/a/28733782/3294412) – musicformellons

回答

1

如果您使用的是django 1.5或更高版本,则可以使用custom user model来代替,这样用户模型将拥有自己的专用表格,然后序列化程序将正确选取字段。

+0

认为这不是一个真正的选择,可能我会用1.4 。我真的不明白这真的很难做到吗?这是为什么?我接近标准的事情,为什么这么复杂? – bradojevic

1

当使用Django Rest Framework时,你必须小心。任何自定义用户模型都不能使用内置的令牌认证。直到你能做到这一点,我会建议在你的自定义模型中与用户一起使用OneToOneField。您的自定义模型将包含您想要保留的额外字段。 One to One可让您从自定义用户以及用户的自定义用户访问该用户。

+5

自发布以来已经差不多一年了 - DRF是否支持Django的自定义用户模型,或者这个答案仍然正确,OneToOneFields与用户仍然是最好的主意? – ArtOfWarfare

12

好吧,几件事情。你想为你的用户模型扩展创建一个OneToOneField。现在

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

,Django的REST框架的力量,是你可以建立自己的序列化,序列化时,来自这两个模型的获取数据。

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

最后,我们的创建用户,由于您使用的自定义字段,你需要实现自己的restore_object()从输入数据建立两个模型。

另外,在Django中创建用户有点不同,你需要调用create_user()并提供一个哈希密码,所以它不像存储序列化程序那样简单。

+0

你可以扩展你的答案,包括'restore_object()'和'create_user()'的示例实现吗?我不确定我应该如何去密码化...(事实上,你甚至建议我们需要这样做,这引起了我的头脑中的红旗 - 不应该让Django或DRF提供这种安全性该框?) – ArtOfWarfare

+0

感谢您的答案!加起来,你也可以使用id属性'user_profile = serializers.CharField(source ='userprofile.id')'。 – pasql

16

显然,我没有足够的声望发表评论下的答案。但是,阐述什么凯文·斯通所描述的,如果你的模型是类似如下:

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

你可以做这样的事情同时创建自定义用户和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 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

请注意,restore_object()与DRF 3.x不兼容,所以您需要改用create()和update()方法。示例:http://www.django-rest-framework.org/topics/3.0-announcement/#serializers。 – jarmod

0

会如果这个用例在文档中更容易找到,那就很好。作为@jamod指出,在DRF 3,你可以找到它here

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

我更喜欢使用Django的signals模块,有事时将信号发送到应用程序,除其他事项外会让你打电话您自己在其他功能之前/之后的功能。我的答案与Stuart的答案类似,但将所有与您的新扩展类相关的代码保存在一个位置(如果您想稍后删除配置文件或更改其名称,则不必在其他位置查看)。

下面的代码展示了扩展类模型,在这种情况下是用户配置文件,然后在创建用户模型时创建一个空实例,然后使用新信息(您必须自己添加)保存实例父用户实例,即 - 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() 

如果没有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') 

在创建用户并保存用户之后,您将有一个空的user.profile来添加信息。例如,运行python manage.py shell 尝试后:

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 
相关问题