drf—— 登录接口,实现头像修改
要求
1 自定义User表扩展auth的User,新增mobile唯一约束字段;新增icon图片字段 2 在自定义User表基础上,用 GenericViewSet + CreateModelMixin + serializer 完成User表新增接口(就是注册接口)
(重要提示:序列化类要重写create方法,不然密码就是明文了) 3 在自定义User表基础上,用 GenericViewSet + RetrieveModelMixin + serializer 完成User表单查(就是用户中心) 4 在自定义User表基础上,用 GenericViewSet + UpdateModelMixin + serializer 完成用户头像的修改
代码
models.py --->数据迁移
from django.db import models from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): mobile = models.CharField(max_length=32, unique=True) icon = models.ImageField(upload_to='head', default='head/default.png')
settings.py
INSTALLED_APPS = [ ... 'rest_framework' ] #打开media路径 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') #扩写auth_user表 AUTH_USER_MODEL = 'app01.UserInfo'
views.py
from django.shortcuts import render from app01.models import UserInfo from app01.serializer import UserModelSerializer, UserReadOnlyModelSerializer, UserIconModelSerializer from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.generics import GenericAPIView from rest_framework.viewsets import GenericViewSet, ViewSetMixin # ViewSetMixin:路由写法变了,自动生成路由 # GenericAPIView:必须指定queryset和serializer class UserView(GenericViewSet, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin): # class UserView(ViewSetMixin,GenericAPIView,CreateModelMixin): queryset = UserInfo.objects.all() serializer_class = UserModelSerializer # 重写get_serializer_class方法,实现不同的请求,返回的序列化类不一样 def get_serializer_class(self): # 可以根据请求方式 if self.action == 'create': return UserModelSerializer elif self.action == 'retrieve': return UserReadOnlyModelSerializer
#更改头像 elif self.action == 'update': return UserIconModelSerializer
serializer.py
from rest_framework import serializers from app01.models import UserInfo from rest_framework.exceptions import ValidationError
class UserModelSerializer(serializers.ModelSerializer): # 注册功能,需要的字段 # username,password,re_password,mobile # 这个字段在表中没有,写成write_only=True re_password = serializers.CharField(max_length=18, min_length=3, required=True, write_only=True) class Meta: model = UserInfo fields = ['username', 'password', 'mobile', 're_password', 'icon'] extra_kwargs = { 'username': {'max_length': 12, 'min_length': 3}, 'password': {'write_only': True}, 'icon': {'read_only': True} } # 写mobile的局部钩子 def validate_mobile(self, data): if len(data) == 11: return data else: raise ValidationError('手机号不合法') # 全局钩子校验两次密码是否一致 def validate(self, attrs): password = attrs.get('password') re_password = attrs.get('re_password') if password == re_password: # re_password不存数据库,剔除 attrs.pop('re_password') return attrs else: raise ValidationError('两次密码不一致') ## 重写create方法,实现密码的加密 #序列化类要重写create方法,不然密码就是明文了 def create(self, validated_data): # re_password也可也在这里移除 # UserInfo.objects.create(**validated_data) # 密码是明文 user = UserInfo.objects.create_user(**validated_data) return user # 注意不要忘了这句话 # 序列化的时候后 # 一个模型类,不一定对着一个序列化类 # 只做序列化用 class UserReadOnlyModelSerializer(serializers.ModelSerializer): class Meta: model = UserInfo fields = ['username', 'mobile', 'icon', 'email', 'date_joined'] # 这个序列化类,只做修改头像用 class UserIconModelSerializer(serializers.ModelSerializer): class Meta: model = UserInfo fields = ['icon', ]
路由分发app01/urls.py
from app01 import views # 自动生成路由 from rest_framework.routers import SimpleRouter router = SimpleRouter() router.register('user', views.UserView) # router.register('userinfo', views.UserReadOnlyView) urlpatterns = [ ... ] urlpatterns += router.urls
总路由urls.py
from django.contrib import admin from django.urls import path,include,re_path from django.views.static import serve from django.conf import settings
urlpatterns = [ path('admin/', admin.site.urls), path('homework/', include('app01.urls')), re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}), ]