【Django开发】django美多商某城项目完整开发4.0第11篇:shou货地址,使用缓存【附代码文档】

🏆🏆🏆教程全知识点简介:1.邮件验证系统包括Django发送邮件、保存邮箱并发送验证邮件、Celery使用Django配置文件设置。2. 地址管理涵盖shou货地址、省市区地址查询、数据库建表、后端接口设计、前端实现、缓存使用(安装、使用方法、省市区视图缓存、缓存数据保存位置和有效期设置)、用户地址管理。3. 数据库设计包括用户部分、产品部分、数据库表设计、表结构、数据库模型类。4. 容器化部署涵盖Docker使用(Ubuntu安装、启动停止、镜像操作)、FastDFS客户端与自定义文件存储系统、页面静态化、定时任务、静态化首页脚本。5. 产品系统包括产品详情页、异步任务触发、脚本工具、用户浏览历史记录(保存、查看)。6. 产品模式涵盖B2B企业对企业、C2C个人对个人、O2O线上到线下、开发流程、需求分析。7. 购wu车系统包括购wu车管理、购wu车数据存储设计(Redis保存已登录用户)、添加到购wu车、查询购wu车数据、登录合并购wu车。8. 订order单系统涵盖提交订order单、我的订order单、订order单评价、订order单结算、保存订order单、MySQL事务隔离级别修改、下单成功页面。9. 搜索系统包括产品搜索、搜索引擎原理、Elasticsearch、Docker安装Elasticsearch扩展、前端实现。10. 支fu系统涉及 集成、Xadmin管理后台。11. 项目配置包括项目准备、配置文件修改、数据库配置、Redis配置、本地化语言时区、异常处理、日志记录。12. 用户认证系统涵盖图片验证码、域名设置、前端Vue代码、跨域CORS、Celery发送短信、账号存在判断、JWT认证(JWT概念、构成、应用、Django REST framework JWT)、 登录(登录流程、模型类创建、urllib使用、回调处理)、用户中心个人信息。

📚📚仓库code.zip 👉直接-->: https://gitee.com/yinuo112/Backend/blob/master/Django/django美多商某城项目完整开发4.0/note.md 🍅🍅
✨ 本教程项目亮点
🧠 知识体系完整:覆盖从基础原理、核心方法到高阶应用的全流程内容
💻 全技术链覆盖:完整前后端技术栈,涵盖开发必备技能
🚀 从零到实战:适合 0 基础入门到提升,循序渐进掌握核心能力
📚 丰富文档与代码示例:涵盖多种场景,可运行、可复用
🛠 工作与学习双参考:不仅适合系统化学习,更可作为日常开发中的查阅手册
🧩 模块化知识结构:按知识点分章节,便于快速定位和复习
📈 长期可用的技术积累:不止一次学习,而是能伴随工作与项目长期参考
🎯🎯🎯全教程总章节
🚀🚀🚀本篇主要内容
shou货地址
在这个页面中, 要实现用户地址的管理,主要的业务逻辑有:
- 省市区地址的数据库建立与查询
- 用户地址的增删改查处理
- 设置默认地址
- 设置地址标题
主要讲解省市区地址的三级联动和缓存,其余留给大家自己来实现。
学习目标:
- 省市区三级联动
- 在Django REST framework中使用缓存
使用缓存
省市区的数据是经常被用户查询使用的,而且数据基本不变化,所以 可以将省市区数据进行缓存处理,减少数据库的查询次数。
在Django REST framework中使用缓存,可以通过drf-extensions
扩展来实现。
关于扩展使用缓存的文档,可参考链接[
安装
pip install drf-extensions
使用方法
1) 直接添加装饰器
可以在使用rest_framework_extensions.cache.decorators中的cache_response装饰器来装饰返回数据的类视图的对象方法,如
[Codecademy Python]
class CityView(views.APIView):
@cache_response()
def get(self, request, *args, **kwargs):
...
cache_response装饰器可以接收两个参数
@cache_response(timeout=60*60, cache='default')
- timeout 缓存时间
- cache 缓存使用的Django缓存后端(即CACHES配置中的键名称)
如果在使用cache_response装饰器时未指明timeout或者cache参数,则会使用配置文件中的默认配置,可以通过如下方法指明:
# DRF扩展
REST_FRAMEWORK_EXTENSIONS = {
# 缓存时间
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 60,
# 缓存存储
'DEFAULT_USE_CACHE': 'default',
}
- DEFAULT_CACHE_RESPONSE_TIMEOUT 缓存有效期,单位秒
- DEFAULT_USE_CACHE 缓存的存储方式,与配置文件中的
CACHES
的键对应。
注意,cache_response装饰器既可以装饰在类视图中的get方法上,也可以装饰在REST framework扩展类提供的list或retrieve方法上。使用cache_response装饰器无需使用method_decorator进行转换。
2)使用drf-extensions提供的扩展类
drf-extensions扩展对于缓存提供了三个扩展类:
- ListCacheResponseMixin
用于缓存返回列表数据的视图,与ListModelMixin扩展类配合使用,实际是为list方法添加了cache_response装饰器
- RetrieveCacheResponseMixin
用于缓存返回单一数据的视图,与RetrieveModelMixin扩展类配合使用,实际是为retrieve方法添加了cache_response装饰器
- CacheResponseMixin
为视图集同时补充List和Retrieve两种缓存,与ListModelMixin和RetrieveModelMixin一起配合使用。
三个扩展类都是在rest_framework_extensions.cache.mixins
中。
为省市区视图添加缓存
因为省市区视图使用了视图集,并且视图集中有提供ListModelMixin和RetrieveModelMixin的扩展(由ReadOnlyModelViewSet提供),所以可以直接添加CacheResponseMixin扩展类。
修改返回省市区信息的视图
from rest_framework_extensions.cache.mixins import CacheResponseMixin
class AreasViewSet(CacheResponseMixin, ReadOnlyModelViewSet):
"""
行政区划信息
"""
pagination_class = None # 区划信息不分页
def get_queryset(self):
"""
提供数据集
"""
if self.action == 'list':
return Area.objects.filter(parent=None)
else:
return Area.objects.all()
def get_serializer_class(self):
"""
提供序列化器
"""
if self.action == 'list':
return AreaSerializer
else:
return SubAreaSerializer
缓存数据保存位置与有效期的设置
想把缓存数据保存在redis中,且设置有效期,可以通过在配置文件中定义的方式来实现。
在配置文件中增加
# DRF扩展
REST_FRAMEWORK_EXTENSIONS = {
# 缓存时间
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 60,
# 缓存存储
'DEFAULT_USE_CACHE': 'default',
}
用户地址管理
为保存用户的地址信息,创建数据库表,在users/models.py中定义模型类
class Address(BaseModel):
"""
用户地址
"""
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses', verbose_name='用户')
title = models.CharField(max_length=20, verbose_name='地址名称')
receiver = models.CharField(max_length=20, verbose_name='shou货人')
province = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='province_addresses', verbose_name='省')
city = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
district = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='district_addresses', verbose_name='区')
place = models.CharField(max_length=50, verbose_name='地址')
mobile = models.CharField(max_length=11, verbose_name='手机')
tel = models.CharField(max_length=20, null=True, blank=True, default='', verbose_name='固定电话')
email = models.CharField(max_length=30, null=True, blank=True, default='', verbose_name='电子邮箱')
is_deleted = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_address'
verbose_name = '用户地址'
verbose_name_plural = verbose_name
ordering = ['-update_time']
说明:
-
Address模型类中的外键指向Areas/models里面的Area,指明外键ForeignKey时,可以使用字符串
应用名.模型类名
来定义 -
related_name 在进行反向关联查询时使用的属性,如
city = models.ForeignKey('areas.Area', related_name='city_addresses')
表示可以通过Area对象.city_addresses属性获取所有相关的city数据。 -
ordering 表名在进行Address查询时,默认使用的排序方式
为User模型类添加默认地址
class User(AbstractUser):
...
default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='默认地址')
...
用户地址管理代码
[Keras 文档]
后端
在users/views.py中添加视图
[PyPDF2 文档] ```python class AddressViewSet(mixins.CreateModelMixin, mixins.UpdateModelMixin, GenericViewSet): """ 用户地址新增与修改 """ serializer_class = serializers.UserAddressSerializer permissions = [IsAuthenticated]
def get_queryset(self):
return self.request.user.addresses.filter(is_deleted=False)
def list(self, request, *args, **kwargs):
"""
用户地址列表数据
"""
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
user = self.request.user
return Response({
'user_id': user.id,
'default_address_id': user.default_address_id,
'limit': constants.USER_ADDRESS_COUNTS_LIMIT,
'addresses': serializer.data,
})
def create(self, request, *args, **kwargs):
"""
保存用户地址数据
"""
# 检查用户地址数据数目不能超过上限
count = request.user.addresses.count()
if count >= constants.USER_ADDRESS_COUNTS_LIMIT:
return Response({'message': '保存地址数据已达到上限'}, status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
"""
处理删除
"""
address = self.get_object()
# 进行逻辑删除
address.is_deleted = True
address.save()
return Response(status=status.HTTP_204_NO_CONTENT)
@action(methods=['put'], detail=True)
def status(self, request, pk=None, address_id=None):
"""
设置默认地址
"""
address = self.get_object()
request.user.default_address = address
request.user.save()
return Response({'message': 'OK'}, status=status.HTTP_200_OK)
@action(methods=['put'], detail=True)
def title(self, request, pk=None, address_id=None):
"""
修改标题
"""
address = self.get_object()
serializer = serializers.AddressTitleSerializer(instance=address, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(ser
- 点赞
- 收藏
- 关注作者
评论(0)