django-Vue搭建博客:用户管理

上一章我们改写了django的认证机制,本章对用户api进行丰富,即用户的增删改查。

用户管理

用户管理涉及到对密码的操作,因此新写一个序列化器,覆写def create(...),def update(...)方法:

# user_info/serializers.py

class UserRegisterSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='user-detail', lookup_field='username')

    class Meta:
        model = User
        fields = [
            'url',
            'id',
            'username',
            'password'
        ]
        extra_kwargs = {
            'password': {'write_only': True}
        }

    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user

    def update(self, instance, validated_data):
        if 'password' in validated_data:
            password = validated_data.pop('password')
            instance.set_password(password)
        return super().update(instance, validated_data)
  • 注意def update(...)时,密码需要单独拿出来通过set_password进行加密,而不能直接保存明文。
  • 超链接字段有一个lookup_fields,这是指定了他解析超链接关系的字段,只管来说,指定其后,连接后面不再是外键id,而是用户名。

用户管理同样涉及的权限问题,因此新建permissions.py,写入以下代码:

# user_info/permissions.py

from rest_framework.permissions import BasePermission, SAFE_METHODS


class IsSelfOfReadOnly(BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.method in SAFE_METHODS:
            return True
        return obj == request.user

这个权限和之前写过的差不多,非安全方法都是只有本人能操作。

到这里很多代码出现重复,介于多个app之间,可以写一个大的Base类进行继承,减少代码量。

铺垫工作做好了,我们在写视图集。

from django.contrib.auth.models import User
from rest_framework import viewsets
from rest_framework.permissions import AllowAny, IsAuthenticatedOrReadOnly

from .permissions import IsSelfOfReadOnly
from .serializers import UserRegisterSerializer


class UserViewset(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserRegisterSerializer
    lookup_field = 'username'

    def get_permissions(self):
        if self.request.method == 'POST':
            self.permission_classes = [AllowAny]
        else:
            self.permission_classes = [IsAuthenticatedOrReadOnly, IsSelfOfReadOnly]
        return super().get_permissions()
  • 注册用户的POST请求时允许所有人都可以操作的,但其他类型的请求(修改,删除)就必须是本人,因此可以覆写def get)permissions
    定义不同情况下所允许的权限。permissions_classes接受列表,因此可以同时定义多个权限,权限之间是and。
  • 注意这里的lookup_field属性,必须和序列化器的对应起来。

注册路由:

from user_info.views import UserViewset
···
router.register(r'user', UserViewset)
···

用户的增删改查就完成了,课件DRF封装层级很高,常规功能完全不需要你去处理。

测试

发送一个get请求:

>http http://127.0.0.1:8000/api/user/
HTTP/1.1 200 OK
...
{
    "count": 3,
    "next": "http://127.0.0.1:8000/api/user/?page=2",
    "previous": null,
    "results": [
        {
            "id": 1,
            "url": "http://127.0.0.1:8000/api/user/xianwei/",
            "username": "xianwei"
        },
        {
            "id": 2,
            "url": "http://127.0.0.1:8000/api/user/Obama/",
            "username": "Obama"
        }
    ]
}

我么会发现,url最后面不再是用户外键id而是username。这就是lookup_field发挥的作用。

其他工作可自行测试。

补充

自定义动作和丰富序列化器:

为了测试,首先修改用户序列化器,即fileds字段:

# user_info/serializers.py
# 新建
class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = [
            'username',
            'last_name',
            'first_name',
            'email',
            'last_login',
            'date_joined'
        ]

修改视图集,添加自定义动作:

# user_info/views.py

from rest_framework.decorators import action
from rest_framework.response import Response
from .serializers import User
from .serializers import UserDetailSerializer

class UserViewset(viewsets.ModelViewSet):
    ...
    @action(detail=True, methods=['get'])
    def info(self, request, username=None):
        queryset = User.objects.get(username=username)
        serializer = UserDetailSerializer(queryset, many=False)
        return Response(serializer.data)

    @action(detail=False)
    def sorted(self, request):
        users = User.objects.all().order_by('-username')

        page = self.paginate_queryset(users)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(users, many=True)
        return Response(serializer.data)

魔法都在装饰器 @action 里,它的参数可以定义是否为详情的动作、请求类型、url 地址、url 解析名等常规需求。

发两个请求试试:

>http http://127.0.0.1:8000/api/user/xianwei/info/
HTTP/1.1 200 OK
...
{
    "date_joined": "2021-06-13T14:58:00",
    "email": "",
    "first_name": "",
    "last_login": null,
    "last_name": "",
    "username": "xianwei"
}
>http http://127.0.0.1:8000/api/user/sorted/
HTTP/1.1 200 OK
...
{
    "count": 3,
    "next": "http://127.0.0.1:8000/api/user/sorted/?page=2",
    "previous": null,
    "results": [
        {
            "url": "http://127.0.0.1:8000/api/user/xianwei/",
            "username": "xianwei"
        },
        {
            "url": "http://127.0.0.1:8000/api/user/root/",
            "username": "root"
        }
    ]
}

这里我把id都去掉了。

默认情况下,方法名就是此动作的路由路径。返回的 Json 也正确显示为方法中所封装的数据。

关于自定义动作详见官方文档

公告

后面一段时间我们以更新pyhotn scrapy框架和分布式爬虫为主,vue前端学习与部属会穿插在里面,感谢支持!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值