Django Vue blog: user management

Posted by dartcol on Sat, 15 Jan 2022 22:16:09 +0100

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!!!

Topics: Python Django