如何在Django Rest Framework中用ApiView不使用Serializer实现学生注册登录API的CRUD?
用DRF的ApiView实现学生注册、登录及CRUD(不使用Serializer)
1. 定义学生模型
先在models.py中创建包含核心字段的Student模型,同时封装密码加密与验证方法:
from django.db import models from django.contrib.auth.hashers import make_password, check_password class Student(models.Model): username = models.CharField(max_length=50, unique=True) email = models.EmailField(unique=True) password = models.CharField(max_length=255) full_name = models.CharField(max_length=100) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def set_password(self, raw_password): self.password = make_password(raw_password) def check_password(self, raw_password): return check_password(raw_password, self.password)
2. 实现注册API(POST)
在views.py中编写注册视图,手动解析请求数据、验证字段唯一性并创建学生对象:
from django.http import JsonResponse from rest_framework.views import APIView from .models import Student import json class StudentRegisterView(APIView): def post(self, request): # 解析请求JSON try: data = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"error": "无效的JSON数据"}, status=400) # 检查必填字段 required_fields = ['username', 'email', 'password', 'full_name'] for field in required_fields: if field not in data: return JsonResponse({"error": f"缺少必填字段: {field}"}, status=400) # 验证用户名/邮箱唯一性 if Student.objects.filter(username=data['username']).exists(): return JsonResponse({"error": "用户名已被占用"}, status=400) if Student.objects.filter(email=data['email']).exists(): return JsonResponse({"error": "邮箱已注册"}, status=400) # 创建学生并加密密码 student = Student( username=data['username'], email=data['email'], full_name=data['full_name'] ) student.set_password(data['password']) student.save() # 返回创建后的学生信息(隐藏密码) return JsonResponse({ "id": student.id, "username": student.username, "email": student.email, "full_name": student.full_name, "created_at": student.created_at.strftime("%Y-%m-%d %H:%M:%S") }, status=201)
3. 实现登录API(POST)
编写登录视图,验证用户名与密码的正确性:
class StudentLoginView(APIView): def post(self, request): try: data = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"error": "无效的JSON数据"}, status=400) username = data.get('username') password = data.get('password') if not username or not password: return JsonResponse({"error": "用户名和密码为必填项"}, status=400) try: student = Student.objects.get(username=username) except Student.DoesNotExist: return JsonResponse({"error": "无效的登录凭证"}, status=401) if not student.check_password(password): return JsonResponse({"error": "无效的登录凭证"}, status=401) # 返回登录成功信息与学生数据 return JsonResponse({ "message": "登录成功", "student": { "id": student.id, "username": student.username, "email": student.email, "full_name": student.full_name } }, status=200)
4. 实现学生CRUD接口
4.1 学生列表接口(GET)
获取所有学生的基础信息:
class StudentListView(APIView): def get(self, request): students = Student.objects.all() student_list = [] for student in students: student_list.append({ "id": student.id, "username": student.username, "email": student.email, "full_name": student.full_name, "created_at": student.created_at.strftime("%Y-%m-%d %H:%M:%S"), "updated_at": student.updated_at.strftime("%Y-%m-%d %H:%M:%S") }) return JsonResponse({"students": student_list}, status=200)
4.2 学生详情/更新/删除接口(GET/PUT/DELETE)
根据学生ID处理单个学生的查询、更新与删除操作:
class StudentDetailView(APIView): def get_object(self, pk): try: return Student.objects.get(pk=pk) except Student.DoesNotExist: return None def get(self, request, pk): student = self.get_object(pk) if not student: return JsonResponse({"error": "学生不存在"}, status=404) return JsonResponse({ "id": student.id, "username": student.username, "email": student.email, "full_name": student.full_name, "created_at": student.created_at.strftime("%Y-%m-%d %H:%M:%S"), "updated_at": student.updated_at.strftime("%Y-%m-%d %H:%M:%S") }, status=200) def put(self, request, pk): student = self.get_object(pk) if not student: return JsonResponse({"error": "学生不存在"}, status=404) try: data = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"error": "无效的JSON数据"}, status=400) # 更新字段逻辑 if 'email' in data: if Student.objects.filter(email=data['email']).exclude(pk=pk).exists(): return JsonResponse({"error": "邮箱已被注册"}, status=400) student.email = data['email'] if 'full_name' in data: student.full_name = data['full_name'] if 'password' in data: student.set_password(data['password']) student.save() return JsonResponse({ "id": student.id, "username": student.username, "email": student.email, "full_name": student.full_name, "updated_at": student.updated_at.strftime("%Y-%m-%d %H:%M:%S") }, status=200) def delete(self, request, pk): student = self.get_object(pk) if not student: return JsonResponse({"error": "学生不存在"}, status=404) student.delete() return JsonResponse({"message": "学生已成功删除"}, status=204)
5. 配置URL路由
在urls.py中完成视图与URL的映射:
from django.urls import path from .views import ( StudentRegisterView, StudentLoginView, StudentListView, StudentDetailView ) urlpatterns = [ path('register/', StudentRegisterView.as_view(), name='student-register'), path('login/', StudentLoginView.as_view(), name='student-login'), path('students/', StudentListView.as_view(), name='student-list'), path('students/<int:pk>/', StudentDetailView.as_view(), name='student-detail'), ]
注意事项
- 手动验证数据时需覆盖必填字段检查、唯一性校验,避免数据库抛出异常
- 必须使用Django内置的哈希方法处理密码,禁止明文存储
- 若需权限控制,可在视图中添加
permission_classes,比如限制仅登录用户修改自身信息 - 登录接口如需持久化会话,可结合Django Session或生成JWT Token(需额外依赖
djangorestframework-simplejwt)
内容的提问来源于stack exchange,提问作者Khushal Sharma
相关产品推荐
相关产品推荐

