木溪商城
约 4573 字大约 15 分钟
2025-10-03
介绍
muxi_shop是一个使用Django和Vue开发的前后端分离的网上上商城项目。具有现代网上商城99%的基础功能(用户注册、浏览商品、添加购物车、下订单、查看订单等功能)
源码地址:
环境准备
系统环境
- Ubuntu Ubuntu 24.04.3 LTS
- python 3.13
python安装pipenv
pip install pipenv创建文件夹django_project并开启虚拟环境
mkdir django_project && cd django_project pipenv shell虚拟环境中下载
djangopip install djangopycharm 配置解释器
- windows中:
~\.virtualenvs\Django_project-2tVlZDRx\Scripts\python.exe - Ubuntu中:
/home/username/.local/share/virtualenvs/myproject-4XG6W5W9/bin/python3
- windows中:
创建项目和APP
django_project/目录下:django-admin startproject muxi_shop_api cd muxi_shop_api mkdir apps && cd apps python ../manage.py startapp user python ../manage.py startapp order python ../manage.py startapp pay python ../manage.py startapp menu python ../manage.py startapp goods python ../manage.py startapp comment python ../manage.py startapp cart python ../manage.py startapp address
APP配置&静态资源配置
muxi_shop_api/settings.py文件中:
注册app
在
INSTALLED_APPS中添加:INSTALLED_APPS = [ ... 'apps.address', 'apps.cart', 'apps.comment', 'apps.goods', 'apps.menu', 'apps.order', 'apps.pay', 'apps.user', ]在
每个app/apps.py中修改Configname,例:# apps/cart/apps.py from django.apps import AppConfig class CartConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'apps.cart' # 在原来的名字前面加上 apps.配置全局静态文件
- 将 资源 (https://github.com/AliceSpring123/Resources) 中的
static文件夹放到项目根目录
# settings.py STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ]- 将 资源 (https://github.com/AliceSpring123/Resources) 中的
URL模块化
在每个app中创建
urls.py文件夹,初始化以下内容:from django.urls import path urlpatterns = []在项目的
urls.py中,将各app的urls.py包含进来urlpatterns = [ path('admin/', admin.site.urls), path('address/', include('apps.address.urls')), path('cart/', include('apps.cart.urls')), path('comment/', include('apps.comment.urls')), path('goods/', include('apps.goods.urls')), path('menu/', include('apps.menu.urls')), path('order/', include('apps.order.urls')), path('pay/', include('apps.pay.urls')), path('user/', include('apps.user.urls')), ]
连接数据库
安装数据库
- Ubuntu
sudo apt update sudo apt install mysql-server - MacOS
brew install mysql # 启动 MySQL 服务 brew services start mysql # 或者手动启动(不随系统启动) mysql.server start
- Ubuntu
运行安全配置脚本(重要)
- Ubuntu
sudo mysql_installation - MacOS
mysql_secure_installation
按照提示进行操作:
- 系统会问你是否要设置 VALIDATE PASSWORD COMPONENT(验证密码插件)。这个插件可以强制要求用户设置强密码。根据你的安全需求选择 Y 或 n。
- 为 MySQL root 用户设置一个强密码。请务必记住这个密码。 后续的问题通常建议都选择 Y (Yes):
- 移除匿名用户?Y
- 禁止远程 root 登录?Y (这能提高安全性)
- 移除测试数据库并对其的访问?Y
- 立即重新加载权限表?Y
- Ubuntu
mysql控制命令Ubuntu
sudo systemctl status mysql # 检查mysql运行状态 sudo systemctl start mysql # 启动mysql sudo systemctl enable mysql # 设置开机自启动MacOS
# 使用 Homebrew 管理服务(推荐) brew services start mysql # 启动 brew services stop mysql # 停止 brew services restart mysql # 重启 brew services list # 查看状态 brew services enable mysql # 启用开机自启 brew services disable mysql # 禁用开机自启mysql
# 使用 root 用户连接 mysql -u root -p # 指定主机和端口 mysql -u root -p -h 127.0.0.1 -P 3306 # 使用特定用户连接 mysql -u username -p # 连接指定数据库 mysql -u root -p database_name
为Django项目创建专用用户和数据库
CREATE DATABASE muxi_shop CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'admin1'@'localhost' IDENTIFIED BY '123qwe'; GRANT ALL PRIVILEGES ON muxi_shop.* TO 'admin1'@'localhost'; FLUSH PRIVILEGES; EXIT;说明:
utf8mb4字符集支持包括表情符号在内的所有Unicode字符,这是现代应用的推荐设置。COLLATE用于设置默认排序规则@'localhost'表示该用户只能从本机连接。如果你的数据库和Django不在同一台机器上,需要修改为主机的IP或%(不推荐,有安全风险)。
下载
pymsqlclientUbuntu
# 安装开发依赖和Python3头文件 sudo apt install python3-dev default-libmysqlclient-dev build-essential pkg-config# 使用 pip 安装 mysqlclient pip install mysqlclientMacOS
brew install mysql-client pkg-config echo 'export LDFLAGS="-L/usr/local/opt/mysql-client/lib"' >> ~/.zshrc echo 'export CPPFLAGS="-I/usr/local/opt/mysql-client/include"' >> ~/.zshrc echo 'export PKG_CONFIG_PATH="/usr/local/opt/mysql-client/lib/pkgconfig"' >> ~/.zshrc source ~/.zshrc# 安装mysqlclient pip install mysqlclient
配置数据库
# settings.py 中修改DATABASE DATABASES = { 'default': { # 数据库引擎(是mysql还是oracle等) 'ENGINE': 'django.db.backends.mysql', # 数据库名 'NAME': 'muxi_shop', # 连接数据库的用户名 'USER': 'admin1', # 连接数据库的密码 'PASSWORD': '123qwe', # 数据库的主机地址 'HOST': '127.0.0.1', # 数据库的端口号 'PORT': '3306', } }
向数据库中写入数据
登入并选择数据库
sudo mysql -u admin1 -p # 输入上面创建的admin1用户的密码123qwe show databases; # 查看admin1的所有数据库 use muxi_shop;创建数据库并写入数据
将此文件(Django/muxi_shop.sql)中的代码复制到命令行执行(近万条数据,全部复制执行即可)

根据数据库自动生成模型类
检查数据库,生成
model代码,将生成的代码保存至每个app的models.py中python manage.py inspectdb --database default user_address > apps/address/models.py python manage.py inspectdb --database default shopping_cart > apps/cart/models.py python manage.py inspectdb --database default comment > apps/comment/models.py python manage.py inspectdb --database default goods > apps/goods/models.py python manage.py inspectdb --database default main_menu sub_menu >> apps/menu/models.py python manage.py inspectdb --database default order order_goods >> apps/order/models.py python manage.py inspectdb --database default user > apps/user/models.py>覆盖>>追加
配置django后台
创建超级用户,以便访问 admin 后台
python manage.py createsuperuser按照提示输入用户名、邮箱和密码
测试
python manage.py runserver在浏览器中打开
http://127.0.0.1:8000/admin/,尝试用刚创建的超级用户登录,确保数据库连接正常。
跨域请求配置
安装
django-cors-headerspip install django-cors-headers在
settings.py文件中配置跨域:# 添加corsheaders到INSTALLED_APPS INSTALLED_APPS = [ ... 'corsheaders', ... ] # 允许所有域名跨域(生产环境慎用!) CORS_ORIGIN_ALLOW_ALL = True # 允许携带cookie CORS_ALLOW_CREDENTIALS = True # 允许的HTTP方法(可选) CORS_ALLOW_METHODS = [ 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', ] # 允许的HTTP头(可选) CORS_ALLOW_HEADERS = [ 'accept', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', ] # 允许特定路径的跨域请求(可选) CORS_URLS_REGEX = r'^/api/.*$' # 预检请求缓存时间(秒)(可选) CORS_PREFLIGHT_MAX_AGE = 86400 # 暴露给浏览器的响应头(可选) CORS_EXPOSE_HEADERS = [] # 添加CorsMiddleware到MIDDLEWARE第一行 # 注释掉CsrfViewMiddleware MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', ... # 'django.middleware.csrf.CsrfViewMiddleware', ... ]
安装Django Rest Framework
接下来的模块开发、序列化与反序列化都需要Django Rest Framework,在这里先安装下
pip install djangorestframework封装全局HttpResponse类
项目根目录新建 utils/BaseResponse.py 用于定义响应体和状态码模板
# utils/BaseResponse.py
from django.http import JsonResponse
from rest_framework import status
from typing import Any, Dict, Optional, List
class APIResponse:
"""
通用API响应类
使用示例:return APIResponse.success(data={'id': 1}, message='操作成功')
响应示例:
{
"success": true,
"code": 200,
"message": "Success",
"data": {}
}
"""
@classmethod
def success(
cls,
data: Any = None,
message: str = "Success",
status_code: int = status.HTTP_200_OK
) -> JsonResponse:
"""
成功响应
"""
response_data = {
"success": True,
"code": status_code,
"message": message,
"data": data if data is not None else {}
}
return JsonResponse(response_data, status=status_code)
@classmethod
def created(
cls,
data: Any = None,
message: str = "Resource created successfully",
status_code: int = status.HTTP_201_CREATED
) -> JsonResponse:
"""
创建成功响应
"""
return cls.success(data, message, status_code)
@classmethod
def error(
cls,
message: str = "Error occurred",
status_code: int = status.HTTP_400_BAD_REQUEST,
errors: Optional[List[Dict]] = None
) -> JsonResponse:
"""
错误响应
"""
response_data = {
"success": False,
"code": status_code,
"message": message,
"errors": errors if errors else []
}
return JsonResponse(response_data, status=status_code)
@classmethod
def not_found(
cls,
message: str = "Resource not found",
status_code: int = status.HTTP_404_NOT_FOUND
) -> JsonResponse:
"""
资源未找到响应
"""
return cls.error(message, status_code)
@classmethod
def validation_error(
cls,
message: str = "Validation error",
errors: Optional[List[Dict]] = None,
status_code: int = status.HTTP_422_UNPROCESSABLE_ENTITY
) -> JsonResponse:
"""
验证错误响应
"""
return cls.error(message, status_code, errors)
@classmethod
def unauthorized(
cls,
message: str = "Unauthorized access",
status_code: int = status.HTTP_401_UNAUTHORIZED
) -> JsonResponse:
"""
未授权响应
"""
return cls.error(message, status_code)
@classmethod
def forbidden(
cls,
message: str = "Forbidden access",
status_code: int = status.HTTP_403_FORBIDDEN
) -> JsonResponse:
"""
禁止访问响应
"""
return cls.error(message, status_code)
@classmethod
def server_error(
cls,
message: str = "Internal server error",
status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR
) -> JsonResponse:
"""
服务器错误响应
"""
return cls.error(message, status_code)
@classmethod
def paginated(
cls,
data: List[Any],
total: int,
page: int,
page_size: int,
message: str = "Success",
status_code: int = status.HTTP_200_OK
) -> JsonResponse:
"""
分页响应
"""
response_data = {
"success": True,
"code": status_code,
"message": message,
"data": {
"items": data,
"pagination": {
"total": total,
"page": page,
"page_size": page_size,
"total_pages": (total + page_size - 1) // page_size if page_size > 0 else 0
}
}
}
return JsonResponse(response_data, status=status_code)
@classmethod
def custom(
cls,
success: bool,
code: int,
message: str,
data: Optional[Any] = None,
errors: Optional[List[Dict]] = None
) -> JsonResponse:
"""
自定义响应
"""
response_data = {
"success": success,
"code": code,
"message": message,
}
if data is not None:
response_data["data"] = data
if errors is not None:
response_data["errors"] = errors
return JsonResponse(response_data, status=code)路由模块化
- 在每个
app下创建文件urls.py - 在项目的
urls.py中包含每个app的urls.pyurlpatterns = [ path('admin/', admin.site.urls), path('menu/', include('apps.menu.urls')), path('goods/', include('apps.goods.urls')), path('order/', include('apps.order.urls')), path('pay/', include('apps.pay.urls')), path('user/', include('apps.user.urls')), path('cart/', include('apps.cart.urls')), path('address/', include('apps.address.urls')), path('comment/', include('apps.comment.urls')), ]
APIs
| 模块 | 描述 | api | 状态 |
|---|---|---|---|
| 分类菜单 | 一级分类菜单 | GET /menu/main_menu | 已完成 |
| 分类菜单 | 二级分类菜单 | GET menu/sub_menu?main_menu_id={main_menu_id} | 已完成 |
商品分类菜单模块开发(/apps/menu/)
功能展示
商品分类菜单就是首页中用于商品分类的一级二级菜单:

整体规划
一共设计两个接口:
- GET
/menu/main_menu- 用于返回一级菜单信息 - GET
menu/sub_menu?main_menu_id={main_menu_id}- 根据main_menu_id返回相应的sub_menu信息
视图开发
# apps/menu/views.py
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from apps.menu.models import MainMenu, SubMenu
from apps.menu.serializers import MainMenuSerializer, SubMenuSerializer
from utils.BaseResponse import APIResponse
# Create your views here.
class GoodsMainMenuAPIView(APIView):
# 获取一级菜单:`GET /main_manu`
def get(self, request):
try:
# 获取main_menu表中所有数据
main_menu = MainMenu.objects.all()
# 序列化操作 django object -> json
result = MainMenuSerializer(instance=main_menu, many=True)
return APIResponse.success(result.data,message='获取一级菜单成功!')
except Exception as e:
return APIResponse.error(message=str(e))
class GoodsSubMenuAPIView(APIView):
# 获取二级菜单:`GET /sub_menu/{main_menu_id}`
def get(self, request, main_menu_id):
try:
sub_menu = SubMenu.objects.filter(main_menu_id=main_menu_id)
# 序列化操作 django object -> json
result = SubMenuSerializer(instance=sub_menu, many=True)
return APIResponse.success(result.data, message=f"获取{main_menu_id}的二级菜单成功!")
except Exception as e:
return APIResponse.error(message=str(e))序列化器
在 /apps/menu/ 新建 serializers.py:
# /apps/menu/serializers.py
from rest_framework import serializers
from apps.menu.models import MainMenu, SubMenu
class MainMenuSerializer(serializers.ModelSerializer):
class Meta:
model = MainMenu
fields = "__all__"
class SubMenuSerializer(serializers.ModelSerializer):
class Meta:
model = SubMenu
fields = "__all__"路由
# apps/menu/urls.py
from django.urls import path
from apps.menu.views import GoodsMainMenuAPIView, GoodsSubMenuAPIView
urlpatterns = [
path('main_menu/', GoodsMainMenuAPIView.as_view(), name='main_menu'),
path('sub_menu/<int:main_menu_id>', GoodsSubMenuAPIView.as_view(), name='submenu'),
]商品类型模块开发(/apps/goods/)
功能展示

整体规划
一共设计两个接口:
- GET
/category/<int:category_id>/<int:page>/- 获取商品列表 - GET
/detail/<int:sku_id>- 获取商品详情
视图开发
# apps/goods/views.py
from django.core.paginator import Paginator
from django.http import JsonResponse
from django.shortcuts import render
from rest_framework.views import APIView
from apps.goods.models import Goods
from apps.goods.serializers import GoodsCategorySerializer
from utils.BaseResponse import APIResponse
# Create your views here.
class GoodsCategoryAPIView(APIView):
# 获取商品列表:/category/<int:category_id>/<int:page>/
def get(self, request, category_id, page):
try:
# 获取查询集
goods_category = Goods.objects.filter(
type_id=category_id,
).all()
# 分页
paginator = Paginator(object_list=goods_category, per_page=20)
page_obj = paginator.get_page(page)
result = GoodsCategorySerializer(instance=page_obj, many=True)
return APIResponse.success(result.data, message=f"获取{category_id}类别下所有商品成功!")
except Exception as e:
return APIResponse.error(message=str(e))
class GoodsDetailAPIView(APIView):
# 获取商品详情:/detail/<int:sku_id>
def get(self, request, sku_id):
try:
# 获取查询集
goods_detail = Goods.objects.filter(
sku_id=sku_id,
).all()
result = GoodsCategorySerializer(instance=goods_detail, many=True)
return APIResponse.success(result.data, message="获取商品详情成功!")
except Exception as e:
return APIResponse.error(message=str(e))序列化器
from rest_framework import serializers
from apps.goods.models import Goods
class GoodsCategorySerializer(serializers.ModelSerializer):
class Meta:
model = Goods
fields = '__all__'路由
from django.urls import path
from apps.goods.views import GoodsCategoryAPIView, GoodsDetailAPIView
urlpatterns = [
path('category/<int:category_id>/<int:page>/', GoodsCategoryAPIView.as_view(), name='goods_category'),
path('detail/<int:sku_id>/', GoodsDetailAPIView.as_view(), name='goods_detail'),
]购物车模块开发(/apps/cart/)
整体规划
一共设计两个接口:
- 获取购物车信息:GET
/cart?email={email} - 添加购物车: POST
/cart
视图开发
from django.db import transaction
from rest_framework.views import APIView
from apps.cart.models import ShoppingCart
from apps.cart.serializers import ShoppingCartSerializer
from utils.BaseResponse import APIResponse
# Create your views here.
class ShoppingCartAPIView(APIView):
# @todo 登录权限验证
# 获取购物车信息:GET `/cart?email={email}`
def get(self, request):
try:
email = request.GET.get('email')
shopping_cart = ShoppingCart.objects.filter(email=email).all()
result = ShoppingCartSerializer(shopping_cart, many=True)
return APIResponse.success(data=result.data, message="获取用户购物车信息成功!")
except Exception as e:
return APIResponse.error(message=str(e))
# 添加购物车 POST `/cart`
def post(self, request):
# 数据验证
serializer = ShoppingCartSerializer(data=request.data)
if not serializer.is_valid():
return APIResponse.error(errors=serializer.errors,message="请求体验证失败!")
request_data = serializer.validated_data
try:
# 使用原子事务确保数据一致性
with transaction.atomic():
# 查找或创建购物车项(使用原子操作)
existed, created = ShoppingCart.objects.select_for_update().get_or_create(
email=request_data['email'],
sku_id=request_data['sku_id'],
is_delete=0,
defaults={
'nums': request_data['nums'],
'is_delete': 0
}
)
# 如果购物车中已存在则更新数量,否则新建加购信息
if not created:
existed.nums += request_data['nums']
existed.save()
# 4. 序列化返回结果
result = ShoppingCartSerializer(instance=existed)
return APIResponse.success(
data=result.data,
message="商品已存在,数量更新成功!" if not created
else "新商品添加购物车成功!"
)
except Exception as e:
# 异常处理
return APIResponse.error(message=f"添加购物车操作失败: {str(e)}")序列化器
from rest_framework import serializers
from apps.cart.models import ShoppingCart
class ShoppingCartSerializer(serializers.ModelSerializer):
class Meta:
model = ShoppingCart
fields = '__all__'路由
from django.urls import path
from apps.cart.views import ShoppingCartAPIView
urlpatterns = [
path('', ShoppingCartAPIView.as_view(),name='shopping_cart'),
]订单模块开发(/apps/order/)
整体规划
- 创建订单预览:POST
/goods - 获取订单详情:GET
/goods/{trade_no}
视图开发
from django.contrib.admin.utils import lookup_field
from rest_framework.generics import GenericAPIView
from apps.order.models import OrderGoods
from apps.order.serializers import OrderGoodsSerializer
from utils.BaseResponse import APIResponse
# Create your views here.
class OrderGoodsGenericAPIView(GenericAPIView):
queryset = OrderGoods.objects.all()
serializer_class = OrderGoodsSerializer
lookup_field = 'trade_no'
lookup_url_kwarg = 'trade_no'
# 创建订单预览:POST `/goods`
def post(self, request):
try:
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return APIResponse.success(message="订单创建成功!")
except Exception as e:
return APIResponse.error(message="创建订单失败!",errors=[{
'errmsg': str(e)
}])
# 获取订单详情:GET `/goods/{trade_no}`
def get(self, request, trade_no):
try:
order_info = self.get_object()
result = self.get_serializer(instance=order_info)
return APIResponse.success(data=result.data, message="获取订单详情成功!")
except Exception as e:
return APIResponse.error(message="获取订单详情失败!", errors=[
{"errmsg":str(e)}
])序列化器
from rest_framework import serializers
from apps.order.models import OrderGoods
class OrderGoodsSerializer(serializers.ModelSerializer):
class Meta:
model = OrderGoods
fields = '__all__'路由
from django.urls import path, re_path
from apps.order.views import OrderGoodsGenericAPIView
urlpatterns = [
path('goods/', OrderGoodsGenericAPIView.as_view(), name='order_goods'),
re_path('goods/(?P<trade_no>.*)', OrderGoodsGenericAPIView.as_view(), name='order_goods'),
]地址模块开发(/apps/address/)
整体规划
- 查看某条地址信息: GET
/address/{pk} - 新建地址:POST
/address - 更改某条地址信息: PUT
/address/{pk} - 查询当前所有地址列表: GET
/address/list
视图开发
from rest_framework import serializers
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from apps.address.models import UserAddress
from apps.address.serializers import AddressSerializer
from utils.BaseResponse import APIResponse
# Create your views here.
class AddressGenericAPIView(GenericAPIView):
queryset = UserAddress.objects.all()
serializer_class = AddressSerializer
# 查看某条地址信息: GET `/address/{pk}`
def get(self, request,pk):
"""
获取单个地址详情
- pk: 地址的主键ID,从URL参数中获取
- 使用get_object()方法自动根据pk查找对象
- 返回序列化后的地址数据
"""
try:
# 自动获取url中的pk,根据pk获取具体的地址对象
address_info = self.get_object()
# 将对象序列化为JSON格式
result = self.get_serializer(instance=address_info)
# 返回序列化后的数据
return APIResponse.success(data=result.data,message="地址信息获取成功!")
except UserAddress.DoesNotExist:
# 如果地址不存在,返回404错误
return APIResponse.error(message="地址不存在!")
# 新建地址:POST `/address`
def post(self, request):
"""
创建新地址
- 从请求体中获取数据
- 验证数据有效性
- 保存到数据库
- 返回创建成功的地址数据
"""
try:
# 接收并反序列化请求体数据
serializer = self.get_serializer(data=request.data)
# 验证数据有效性
serializer.is_valid(raise_exception=True)
# 保存数据至数据库
serializer.save()
return APIResponse.success("新建地址成功!")
except Exception as e:
return APIResponse.error(message="创建地址失败",errors=[{
'errmsg': str(e)
}])
# 更改某条地址信息: PUT `/address/{pk}`
def put(self, request,pk):
"""
完整更新地址信息
- pk: 要更新的地址主键ID
- 需要提供所有必填字段(PUT是完整更新)
- 验证数据后保存更新
"""
try:
# 自动获取url中的pk,根据pk获取具体的地址对象
address_info = self.get_object()
# 从数据库中获取的现有对象address_info,告诉序列化器:"用户想要将address_info更新成request.data"
serializer = self.get_serializer(instance=address_info, data=request.data)
# 验证数据有效性
serializer.is_valid(raise_exception=True)
serializer.save()
return APIResponse.success(message="地址更新成功!")
except Exception as e:
return APIResponse.error(message="地址更新失败",errors=[{
'errmsg': str(e)
}])
# 删除某条地址: DELETE `/address/{pk}`
def delete(self, request,pk):
try:
address_info = self.get_object() # 自动从URL获取pk
address_info.delete()
return APIResponse.success(message="地址删除成功!")
except UserAddress.DoesNotExist:
return APIResponse.error(message="地址删除失败:地址不存在!")
except Exception as e:
return APIResponse.error(message="地址删除失败",errors=[{
'errmsg': str(e)
}])
class AddressListGenericAPIView(GenericAPIView):
queryset = UserAddress.objects.all()
serializer_class = AddressSerializer
# 查询当前所有地址列表: GET `/address/list`
def get(self,request):
try:
address_list = self.get_queryset()
result = self.get_serializer(instance=address_list,many=True)
return APIResponse.success(data=result.data,message="地址列表获取成功!")
except Exception as e:
# 异常处理
return APIResponse.error(
message="获取地址列表失败",
errors=[{
'errmsg': str(e)
}]
)序列化器
from rest_framework import serializers
from apps.address.models import UserAddress
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = UserAddress
fields = '__all__'路由
from django.urls import path, re_path
from apps.address.views import AddressGenericAPIView, AddressListGenericAPIView
urlpatterns = [
path('', AddressGenericAPIView.as_view()),
path('list/', AddressListGenericAPIView.as_view()),
re_path('(?P<pk>.*)', AddressGenericAPIView.as_view()),
]用户模块开发(/apps/xxx/)
整体规划
- 查看个人信息: GET
/user/detail - 用户注册: POST
/user/register - 用户登录: POST
/user/login
视图开发
from django.db import transaction
from django.shortcuts import render
from rest_framework.views import APIView
from apps.user.models import User
from apps.user.serializers import UserSerializer
from utils.BaseResponse import APIResponse
# Create your views here.
class UserAPIView(APIView):
# 查看个人信息: GET `/user?email={email}`
def get(self, request):
email = request.GET.get("email")
try:
user_info = User.objects.get(email=email)
result = UserSerializer(instance=user_info)
return APIResponse.success(data=result.data, message="个人信息查询成功")
except User.DoesNotExist:
return APIResponse.error(message="个人信息查询失败,用户不存在!")
# 用户注册: POST `/user`
def post(self, request):
"""
用户注册接口
- 验证用户数据
- 创建用户账户
- 返回创建的用户信息
"""
# 复制数据以避免修改原始请求数据
request_data = request.data.copy()
try:
# 验证请求数据
serializer = UserSerializer(data=request_data)
serializer.is_valid(raise_exception=True)
# 创建用户(使用事务保证原子性)
with transaction.atomic():
user = serializer.save()
# 返回前端
result = UserSerializer(instance=user)
return APIResponse.success(data=result.data, message="注册成功")
except Exception as e:
# 记录日志(实际项目中应该添加日志记录)
# logger.error(f"用户注册失败: {str(e)}")
return APIResponse.error(
message="注册失败,请稍后重试",
errors=[{"errmsg": str(e)}],
)信息加密
# apps/user/pwd_encoder.py
import hashlib
# 明文密码md5加密
def get_md5(password):
md5 = hashlib.md5()
md5.update(password.encode())
return md5.hexdigest()序列化器
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from apps.user.models import User
from apps.user.pwd_encoder import get_md5
import datetime
class UserSerializer(serializers.ModelSerializer):
# email作为账户名, 需要唯一性验证
email = serializers.EmailField(
# 必须
required=True,
# 不允许空
allow_null=False,
# 唯一性校验
validators=[UniqueValidator(queryset=User.objects.all(), message="用户已存在")]
)
# 时间格式化
birthday = serializers.DateTimeField('%Y-%m-%d %H:%M:%S')
create_time = serializers.DateTimeField('%Y-%m-%d %H:%M:%S', required=False)
# 在调用save()时自动被调用,在数据存储之前进行加工
def create(self, validated_data):
# 密码md5加密
validated_data['password'] = get_md5(validated_data['password'])
# 取当前时间为注册时间
validated_data['create_time'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
result = User.objects.create(**validated_data)
return result
class Meta:
model = User
fields = "__all__"
# 创建用户后密码不返回给前端
extra_kwargs = {'password': {'write_only': True}}路由
from django.urls import path
from apps.user.views import UserAPIView
urlpatterns = [
path('', UserAPIView.as_view(), name="user"),
]商品评论模块开发(/apps/comment/)
整体规划
视图开发
from django.shortcuts import render
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
from apps.comment.models import Comment
from apps.comment.serializers import CommentSerializer
# Create your views here.
class CommentGenericAPIView(ModelViewSet, ReadOnlyModelViewSet):
queryset = Comment.objects
serializer_class = CommentSerializer
def single(self, request, pk):
print("我是查询一个")
return self.retrieve(request, pk)
def my_list(self, request):
print("我是查询多个")
return self.list(request)
def edit(self, request, pk):
print("更新")
return self.update(request, pk)
def my_save(self, request):
print("我是保存")
return self.create(request)
def my_delete(self, request, pk):
print("我是删除")
return self.destroy(request, pk)序列化器
from rest_framework import serializers
from apps.address.models import UserAddress
from apps.comment.models import Comment
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'路由
from django.urls import path, re_path
from apps.address.views import AddressGenericAPIView, AddressListGenericAPIView
from apps.comment.views import CommentGenericAPIView
urlpatterns = [
path('', CommentGenericAPIView.as_view({
"get":"my_list",
}
)),
re_path('(?P<pk>.*)', CommentGenericAPIView.as_view({
"get":"single"
})),
]xxx 模块开发(/apps/xxx/)
功能展示
整体规划
视图开发
序列化器
路由
xxx 模块开发(/apps/xxx/)
功能展示
整体规划
视图开发
序列化器
路由
xxx 模块开发(/apps/xxx/)
功能展示
整体规划
视图开发
序列化器
路由
