【问题标题】:How to implement nested serializer in django rest framework?如何在 django rest 框架中实现嵌套序列化器?
【发布时间】:2016-10-01 02:41:36
【问题描述】:

我正在扩展 django auth 表的用户模型并为它实现 rest api。

我不知道如何实现相同的 GET/POST 请求。

我的models.py代码是:

class UserProfile(models.Model):
    """User profile model for information about user."""

    users = models.OneToOneField(User)
    phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'")
    phone_number = models.CharField(max_length=100, validators=[phone_regex], blank=True)
    created_timestamp = models.DateTimeField(auto_now_add=True, null=True)
    updated_timestamp = models.DateTimeField(auto_now=True, null=True)

我的 serializers.py 代码是:

class UserSerializer(serializers.ModelSerializer):
    """Serializer for users."""

    class Meta:
        model = User


class UserProfileSerializer(serializers.ModelSerializer):
    """Serializer for user profiles."""

    users = UserSerializer(many=True)

    class Meta:
        model = UserProfile

    def create(self, validated_data):
        users_data = validated_data.pop('users')
        print 'yes'
        print users_data
        user_profile = UserProfile.objects.create(**validated_data)
        for user_data in users_data:
            user_data, created = User.objects.get_or_create(first_name=user_data['first_name'], last_name=user_data['last_name'],
        username=user_data['username'], password=user_data['password'], email=user_data['email'], is_active=['is_active'])
        user_profile.users.add(user_data)
    return user_profile

我的 v1.py 代码是:

class UserProfileList(APIView):
    """Get and post user profiles data."""

    def get(self, request, format=None):
        """Get users."""
        user_profiles = UserProfile.objects.all()
        serialized_user_profiles = UserProfileSerializer(user_profiles, many=True)
        return Response(serialized_user_profiles.data)

    def post(self, request, format=None):
        """Post users."""
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

我认为问题出在 v1.py 文件中。我想发出 GET 和 POST 请求,对于 POST 请求,我想发送 JSON 数据。有人可以帮我实现它。实际上,我想要一个端点来发出 POST 请求并将数据存储在 User 模型和 UserProfile 模型中。

【问题讨论】:

    标签: json django python-2.7 django-rest-framework serialization


    【解决方案1】:

    修改上面的代码

    models.py

    class UserProfile(models.Model):
        user = models.OneToOneField(User)
        phone_number = models.CharField(max_length=100, validators=[
        RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'")
        ], blank=True, null=True)
        created_timestamp = models.DateTimeField(auto_now_add=True, null=True)
        updated_timestamp = models.DateTimeField(auto_now=True, null=True)
    

    序列化器.py

    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
    
    class UserProfileSerializer(serializers.ModelSerializer):
        user = UserSerializer(required=True)
        class Meta:
            model = UserProfile
    
        def create(self, validated_data):
            user_data = validated_data.pop('user', None)
            user = User.objects.create_user(**user_data)
            return UserProfile.objects.create(user=user, **validated_data)
    
       def update(self, instance, validated_data):
           user_dict = validated_data.pop('user', None)
           if user_dict:
               user_obj = instance.user
               for key, value in user_dict.iteritems():
                    setattr(user_obj, key, value)
               user_obj.save()
               validated_data["user"] = user_obj
           for key, value in validated_data.iteritems():
               setattr(instance, key, value)
           instance.save()
           return instance
    

    viewsets.py

    from rest_framework import mixins
    from rest_framework import viewsets
    
    class MyUserViewSet(mixins.UpdateModelMixin,
                        mixins.CreateModelMixin,
                        mixins.ListModelMixin,
                        viewsets.GenericViewSet):
    
        authentication_classes = (TokenAuthentication, SessionAuthentication)
        permission_classes = (AllowAny, )
        serializer_class = UserProfileSerializer
        queryset = UserProfile.objects.all()
    

    点击此链接routers

    routers.py

    from rest_framework import routers
    router = routers.SimpleRouter()
    router.register('users', MyUserViewSet)
    

    urls.py

    from .routers import router
    urlpatterns = patterns(
        url(r'^api/v1/', include(router.urls)),
    )
    

    【讨论】:

    • 我在 urls.py 文件中使用了url(r'^v1/users/$', csrf_exempt(userregistration.v1.MyUserViewSet.as_view({'get': 'queryset'}))),,但出现错误'QuerySet' object is not callable
    • 您在 get 参数中映射queryset,您需要映射 {"get": "list"} 。关注此链接django-rest-framework.org/api-guide/routers/#example
    • 我试过但收到错误'MyUserViewSet' object has no attribute 'list'
    • 我应该也为它写路线
    【解决方案2】:

    我建议您通过继承 AbstractBaseUser 来扩展 User 模型,这也需要继承 BaseUserManager。这样你就可以通过只有一个类来简化你的序列化器。它还需要 BaseUserManager 的子类化。

    自定义用户可以拥有任意数量的自定义字段。以这种方式扩展用户模型通常比创建与默认用户模型的一对一关系更简单。它可以为您节省一些逻辑和一些时间。

    您可以在此处阅读更多内容: https://docs.djangoproject.com/ja/1.9/topics/auth/customizing/#specifying-a-custom-user-model

    这是一个示例,说明您将如何创建 BaseUserManager 的子类:

    class MyUserManager(BaseUserManager):
        def create_user(self, email=None, password=None, dateofbirth=None, username=None):
            user = self.model(
                email=MyUserManager.normalize_email(email),    
                dateofbirth=dateofbirth,
                username=username
            )
    
            user.set_password(password)
            user.save(using=self._db)
            return user
    
        def create_superuser(self, username, dateofbirth, email, password):
            user = self.create_user(email=email,
                        password=password,
                        username=username,
                        dateofbirth=dateofbirth,
                    )
            user.is_superuser = True
            user.save(using=self._db)
            return user
    

    这是一个继承 AbstractBaseUser 的例子:

    class MyUser(AbstractBaseUser):
    
        email = models.EmailField(
            verbose_name='email address',
            max_length=255,
            unique=True
        )
    
        dateofbirth = models.CharField(max_length=30, blank=True)
    
        is_active = models.BooleanField(default=True)
        is_superuser = models.BooleanField(default=False)
    
        USERNAME_FIELD = 'email'
    
        objects = MyUserManager()
    
        def get_full_name(self):
            return self.email
    
        def get_short_name(self):
            return self.email
    
        def __unicode__(self):
            return self.email
    
        def has_perm(self, perm, obj=None):
            return True
    
        def has_module_perms(self, app_label):
            return True
    
        @property
        def is_staff(self):
            return self.is_superuser
    

    为此,您必须在 settings.py 中设置 auth 用户模型,以让您的 django 应用知道您正在使用自定义用户模型:

    AUTH_USER_MODEL = 'myapp.MyUser'
    

    这是最简单的部分 - 序列化程序:

    class MyUserSerializer(serializers.ModelSerializer):
        password = serializers.CharField(write_only=True, required=True)
    
        class Meta:
            model = MyUser
            fields = (
                'email',
                'password',
                'dateofbirth',
                'username',
            )
    
        def create(self, validated_data):
            password = validated_data.pop("password", None)
            email = validated_data.pop("email", None)
            username = validated_data.pop("username", None)
            user = MyUser.objects.create_user(email=email, password=password, username=username, gender=gender, dateofbirth=dateofbirth)
            MyUser.objects.filter(id=user.id).update(**validated_data)
            return user
    

    当您使用它时,忘记 APIView 并使用更简单的 ViewSet:

    class MyUserViewSet(viewsets.ModelViewSet):
        authentication_classes = (TokenAuthentication, SessionAuthentication)
        permission_classes = (AllowAny, )
        serializer_class = MyUserSerializer
    

    仅此一项,您就可以处理所有 GET、POST、PUT、DELETE 请求。

    【讨论】:

      猜你喜欢
      • 2018-12-13
      • 2021-06-23
      • 2016-08-01
      • 2014-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 2017-11-15
      相关资源
      最近更新 更多