首页 文章

Django REST框架创建自定义用户

提问于
浏览
17

我是Django领域的新手,但看到那里有很多“神奇” . 我正在使用Django REST Framework并创建允许免费用户注册的应用程序 . 我的用户需要一些Django用户不具备的其他字段 . 所以我用Google搜索扩展用户 . 有一种想法应该通过创建这样的东西来完成

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')

所以,问题是这个序列化器在这里做了一些“魔术” . 它试图找出应该建模的字段...我想让用户在这里列出字段,这些字段在User中,'city'是新的自定义字段 . Serializer没有得到应该在用户模型中查看 .

我在这里错过了什么?如何告诉这个序列化器我想要用户内的一些字段?我也需要能够创建用户 .

6 回答

  • 1

    显然,我没有足够的声誉在答案下发表评论 . 但是要详细说明凯文斯通所描述的内容,如果你的模型如下:

    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)
    
  • 18

    好的,有几件事 . 您想为您的用户模型扩展创建 OneToOneField .

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

    现在,Django Rest Framework的强大之处在于,您可以构建序列化程序,在序列化时从这两个模型中获取数据 .

    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() 并提供经过哈希处理的密码,因此它不像从序列化程序存储字段那么简单 .

  • 1

    如果您正在使用django 1.5或更高版本,那么请使用custom user model,这样用户模型将拥有它自己的专用表,然后序列化器将正确地拾取字段 .

  • 1

    使用Django Rest Framework时,您必须小心 . 任何自定义用户模型都无法使用内置令牌身份验证 . 在你能做到这一点之前,我建议你在自定义模型中使用OneToOneField和用户 . 您的自定义模型将包含您要保留的额外字段 . 一对一允许您从自定义用户和用户的自定义用户访问用户 .

  • 1

    如果这个用例在文档中更容易找到,那就太好了 . 正如@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
    
  • 13

    我更喜欢使用django signals模块,它会在发生某些事情时向应用程序发送信号,除此之外还可以让你在其他功能之前/之后调用自己的功能 . 我的答案类似于Stuart 's answer but keeps all of the code relevant to your new extension class in one place (if you want to delete the profile later or change its name you don' t必须在其他任何地方看 .

    下面的代码列出了您的扩展类模型,在本例中是用户配置文件,然后在创建用户模型时创建一个空实例,然后通过保存父用户实例来保存具有新信息的实例(您必须自己添加) - 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
    

相关问题