DRF 用户系统实战 #
一、用户系统概述 #
1.1 功能需求 #
- 用户注册
- 用户登录(JWT)
- 个人资料管理
- 密码修改
- 头像上传
1.2 技术栈 #
- Django REST Framework
- djangorestframework-simplejwt
- Pillow
二、用户模型 #
2.1 扩展用户模型 #
python
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
phone = models.CharField(max_length=20, blank=True)
bio = models.TextField(max_length=500, blank=True)
birth_date = models.DateField(null=True, blank=True)
website = models.URLField(blank=True)
class Meta:
verbose_name = '用户'
verbose_name_plural = '用户'
2.2 配置 #
python
AUTH_USER_MODEL = 'users.User'
三、序列化器 #
3.1 注册序列化器 #
python
class UserRegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, min_length=8)
password_confirm = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'password', 'password_confirm', 'phone']
def validate_email(self, value):
if User.objects.filter(email=value).exists():
raise serializers.ValidationError('该邮箱已被注册')
return value
def validate(self, data):
if data['password'] != data['password_confirm']:
raise serializers.ValidationError({'password_confirm': '两次密码不一致'})
return data
def create(self, validated_data):
validated_data.pop('password_confirm')
user = User.objects.create_user(**validated_data)
return user
3.2 用户序列化器 #
python
class UserSerializer(serializers.ModelSerializer):
articles_count = serializers.SerializerMethodField()
followers_count = serializers.SerializerMethodField()
class Meta:
model = User
fields = ['id', 'username', 'email', 'avatar', 'phone', 'bio',
'birth_date', 'website', 'articles_count', 'followers_count']
read_only_fields = ['id', 'username']
def get_articles_count(self, obj):
return obj.articles.count()
def get_followers_count(self, obj):
return obj.followers.count()
3.3 密码修改序列化器 #
python
class PasswordChangeSerializer(serializers.Serializer):
old_password = serializers.CharField(write_only=True)
new_password = serializers.CharField(write_only=True, min_length=8)
new_password_confirm = serializers.CharField(write_only=True)
def validate_old_password(self, value):
user = self.context['request'].user
if not user.check_password(value):
raise serializers.ValidationError('旧密码错误')
return value
def validate(self, data):
if data['new_password'] != data['new_password_confirm']:
raise serializers.ValidationError({'new_password_confirm': '两次密码不一致'})
return data
def save(self):
user = self.context['request'].user
user.set_password(self.validated_data['new_password'])
user.save()
return user
四、JWT配置 #
4.1 安装和配置 #
python
INSTALLED_APPS = [
...
'rest_framework_simplejwt',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'AUTH_HEADER_TYPES': ('Bearer',),
}
4.2 自定义Token视图 #
python
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
token['username'] = user.username
token['email'] = user.email
return token
def validate(self, attrs):
data = super().validate(attrs)
data['user'] = UserSerializer(self.user).data
return data
class CustomTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer
五、视图 #
5.1 用户视图集 #
python
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
def get_serializer_class(self):
if self.action == 'create':
return UserRegisterSerializer
if self.action == 'change_password':
return PasswordChangeSerializer
return UserSerializer
def get_permissions(self):
if self.action == 'create':
return [AllowAny()]
if self.action in ['update', 'partial_update', 'destroy', 'change_password']:
return [IsAuthenticated(), IsOwner()]
return [AllowAny()]
@action(detail=False, methods=['get', 'put', 'patch'])
def me(self, request):
if request.method == 'GET':
serializer = self.get_serializer(request.user)
return Response(serializer.data)
serializer = self.get_serializer(
request.user,
data=request.data,
partial=request.method == 'PATCH'
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
@action(detail=False, methods=['post'])
def change_password(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({'message': '密码修改成功'})
@action(detail=False, methods=['post'])
def upload_avatar(self, request):
if 'avatar' not in request.FILES:
return Response({'error': '请选择图片'}, status=400)
user = request.user
user.avatar = request.FILES['avatar']
user.save()
return Response({'avatar': user.avatar.url})
六、URL配置 #
python
from rest_framework.routers import DefaultRouter
from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView
from .views import UserViewSet, CustomTokenObtainPairView
router = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = [
path('', include(router.urls)),
path('token/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]
七、API接口 #
| 接口 | 方法 | 说明 |
|---|---|---|
| /api/users/ | POST | 用户注册 |
| /api/users/me/ | GET | 获取个人信息 |
| /api/users/me/ | PUT | 更新个人信息 |
| /api/token/ | POST | 登录获取Token |
| /api/token/refresh/ | POST | 刷新Token |
| /api/users/change_password/ | POST | 修改密码 |
八、总结 #
本章实现了完整的用户系统:
- 用户注册和登录
- JWT Token认证
- 个人资料管理
- 密码修改
- 头像上传
用户系统是API的核心基础!
最后更新:2026-03-28