In the previous chapter, we rewritten the authentication mechanism of django. This chapter enriches the user api, that is, the addition, deletion, modification and query of users.
user management
User management involves operations on passwords, so write a new serializer and override def create(...),def update(...) method:
# 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)
- Note def update(...) The password needs to be taken out separately through set_password is encrypted, but plaintext cannot be saved directly.
- The hyperlink field has a lookup_fields, which specifies the field for him to resolve the hyperlink relationship. After specifying, the connection is no longer followed by the foreign key id, but the user name.
User management also involves permission issues, so create permissions Py, write the following code:
# 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
This permission is similar to what I have written before. Only I can operate non secure methods.
Here, many codes are repeated, between multiple app s. You can write a large Base class for inheritance to reduce the amount of code.
The groundwork is done. We are writing a visual atlas.
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()
- When registering a user's POST request, everyone is allowed to operate, but other types of requests (modification, deletion) must be personal, so def (get) permissions can be overridden
Define the permissions allowed in different situations. permissions_classes accepts lists, so you can define multiple permissions at the same time, and between permissions. - Notice the lookup here_ The field property must correspond to the of the serializer.
Register route:
from user_info.views import UserViewset ··· router.register(r'user', UserViewset) ···
The user's addition, deletion, modification and query are completed. The courseware DRF packaging level is very high, and the conventional functions do not need you to deal with at all.
test
Send a get request:
>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" } ] }
We will find that the last side of the url is no longer the user's foreign key id, but the user name. This is lookup_ The role of field.
Other work can be tested by yourself.
supplement
Custom actions and rich serializers:
To test, first modify the user serializer, that is, the files field:
# user_info/serializers.py # newly build class UserDetailSerializer(serializers.ModelSerializer): class Meta: model = User fields = [ 'username', 'last_name', 'first_name', 'email', 'last_login', 'date_joined' ]
Modify the view set and add custom actions:
# 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)
Magic is in the decorator @ action. Its parameters can define whether it is a detailed action, request type, url address, url resolution name and other general requirements.
Try sending two requests:
>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" } ] }
I've removed all the IDS here.
By default, the method name is the routing path for this action. The returned Json is also correctly displayed as the data encapsulated in the method.
For more information about custom actions, see Official documents.
Notice
Later, we will mainly update the pyhotn sweep framework and distributed crawlers. vue front-end learning and subordinates will be interspersed in it. Thank you for your support!!!