开源web框架django知识总结(十三)

开源web框架django知识总结(十三)

省市区三级联动

展示收货地址界面

提示:

  • 省市区数据是在收货地址界面展示的,所以我们先渲染出收货地址界面。
  • 收货地址界面中基础的交互已经提前实现。

1.新建app areas,新建子urls.py,同步,注册areas,

python ../../manage.py startapp areas

  1. 准备省市区模型和数据 areas.models.py
class Area(models.Model):
"""
    行政区划
"""

    name = models.CharField(max_length=20,
                            verbose_name='名称')

    parent = models.ForeignKey('self',
                               on_delete=models.SET_NULL,
                               related_name='subs',
                               null=True,
                               blank=True,
                               verbose_name='上级行政区划')

    class Meta:
        db_table = 'tb_areas'
        verbose_name = '行政区划'
        verbose_name_plural = '行政区划'

    def __str__(self):
        return self.name

迁移模型类

python manage.py makemigrations
python manage.py migrate

模型说明:

  • 自关联字段的外键指向自身,所以 models.ForeignKey('self')
  • 反向查询:没有外键属性一方,可以调用反向属性查询到关联的另一方。 反向关联属性为”实例对象.引用类名(小写)”,使用
related_name

指明父级查询子级数据的语法

  • 默认 Area模型类对象.area_set语法
related_name='subs'

*
– 现在 Area模型类对象.subs语法

导入省市区数据:在项目根目录下建立scripts文件夹,将数据库文件areas.sql拷贝进来,在xshell进入到目录中执行下面语句。


mysql -usuifeng -p123456  -D aerf_mall < areas.sql

注意:如果出现错误信息:

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’ (2)

应该配置为 bind-address=0.0.0.0,并且这行应该加在 /etc/mysql/mysql.conf.d/mysqld.cnf 配置文件里.

也可以重启一下虚拟机试试,或者用下面的方法:


mysql -h127.0.0.1 -usuifeng -p123456  -D aerf_mall < areas.sql

开源web框架django知识总结(十三)

3. 查询省市区数据

1.请求方式

选项方案
请求方法

GET
请求地址

/areas/

2.请求参数:查询参数

  • 如果前端没有传入 area_id,表示用户需要省份数据
  • 如果前端传入了 area_id,表示用户需要市或区数据

参数名类型是否必传说明
area_id

string否地区ID

3.响应结果:JSON

  • 省份数据
{
  "code":"0",
  "errmsg":"OK",
  "province_list":[
      {
          "id":110000,
          "name":"北京市"
      },
      {
          "id":120000,
          "name":"天津市"
      },
      {
          "id":130000,
          "name":"河北省"
      },
      ......

  ]
}

市或区数据

{
  "code":"0",
  "errmsg":"OK",
  "sub_data":{
      "id":130000,
      "name":"河北省",
      "subs":[
          {
              "id":130100,
              "name":"石家庄市"
          },
          ......

      ]
  }
}

4.查询省市区数据后端逻辑实现

  • 如果前端没有传入 area_id,表示用户需要省份数据
  • 如果前端传入了 area_id,表示用户需要市或区数据

获取可选省份信息、获取可选市区信息 areas.views.py

from django.views import View
from django.http import JsonResponse
from .models import Area
from django.core.cache import cache

class ProvinceAreasView(View):

    def get(self, request):

        p_list = cache.get('province_list')

        if not p_list:

            provinces = Area.objects.filter(
                parent=None
            )

            p_list = []
            for province in provinces:

                p_list.append({
                    'id': province.id,
                    'name': province.name
                })

            cache.set('province_list', p_list, 3600)

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'province_list': p_list
        })

class SubAreasView(View):

    def get(self, request, pk):

        sub_data = cache.get('sub_area_%s'%pk)

        if not sub_data:

            p_area = Area.objects.get(
                pk=pk
            )

            subs = Area.objects.filter(
                parent_id=pk
            )

            sub_list = []
            for sub in subs:

                sub_list.append({
                    'id': sub.id,
                    'name': sub.name
                })

            sub_data = {
                    'id': p_area.id,
                    'name': p_area.name,
                    'subs': sub_list
            }

            cache.set('sub_area_%s'%pk, sub_data, 3600)

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'sub_data': sub_data
        })

5. areas.urls.py

from django.urls import re_path
from . import views

urlpatterns = [
    re_path(r'^areas/$', views.ProvinceAreasView.as_view()),
    re_path(r'^areas/(?P[1-9]\d+)/$', views.SubAreasView.as_view()),
]

收货地址

开源web框架django知识总结(十三)
开源web框架django知识总结(十三)

用户地址的主要业务逻辑有:

  1. 展示省市区数据
  2. 用户地址的增删改查处理
  3. 设置默认地址
  4. 设置地址标题

==============================

新增地址前后端逻辑

1. 定义用户地址模型类 user.models.py

1.用户地址模型类

from aerf_mall.utils.BaseModel import BaseModel
class Address(BaseModel):
"""
    用户地址
"""
    user = models.ForeignKey(User,
                             on_delete=models.CASCADE,
                             related_name='addresses',
                             verbose_name='用户')

    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='区')

    title = models.CharField(max_length=20, verbose_name='地址名称')
    receiver = models.CharField(max_length=20, 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_addresses'
        verbose_name = '用户地址'
        verbose_name_plural = verbose_name

        ordering = ['-update_time']

注释1:Django中related_name作用

2.Address模型类说明

  • Address模型类中的外键指向 areas/models里面的 Area。指明外键时,可以使用 &#x5E94;&#x7528;&#x540D;.&#x6A21;&#x578B;&#x7C7B;&#x540D;来定义。
    *
ordering

表示在进行排序展示

Address

查询时,默认使用的排序方式。
ordering = ['-update_time'] : 根据更新的时间倒叙。

3.补充用户模型默认地址字段

class User(AbstractUser):
    """自定义用户模型类"""
    mobile = models.CharField(
        unique=True,
        verbose_name='手机号',
        null=True,
        max_length=11
    )

    email_active = models.BooleanField(default=False,verbose_name='邮箱验证状态')

    default_address = models.ForeignKey('Address',
                                        related_name='users',
                                        null=True,
                                        blank=True,
                                        on_delete=models.SET_NULL,
                                        verbose_name='默认地址')

    class Meta:
        db_table = 'tb_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

执行数据迁移:

python manage.py makemigrations
python manage.py migrate

2. 新增地址接口设计和定义

1.请求方式

选项方案
请求方法

POST
请求地址

/addresses/create/

2.请求参数:JSON

参数名类型是否必传说明
receiver

string是收货人
province_id

string是省份ID
city_id

string是城市ID
district_id

string是区县ID
place

string是收货地址
mobile

string是手机号
tel

string否固定电话
email

string否邮箱

3.响应结果:JSON

字段说明
code

状态码
errmsg

错误信息
id

地址ID
receiver

收货人
province

省份名称
city

城市名称
district

区县名称
place

收货地址
mobile

手机号
tel

固定电话
email

邮箱

3. 新增地址后端逻辑实现 users.views.py

提示:

  • 用户地址数量有上限,最多20个,超过地址数量上限就返回错误信息
from .models import Address

class CreateAddressView(View):

    def post(self, request):

        data = json.loads(request.body.decode())
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')

        user = request.user
        count = Address.objects.filter(user=user).count()
        if count >= 10:
            return JsonResponse({'code': 400, 'errmsg': '数量超限'})

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({"code": 400, 'errmsg': '缺少参数!'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'errmsg': '参数mobile有误'})
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return JsonResponse({'code': 400,
                                     'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400,
                                     'errmsg': '参数email有误'})

        try:
            address = Address.objects.create(
                user=user,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                title=receiver,
                receiver=receiver,
                place=place,
                mobile=mobile,
                tel=tel
            )

            if not user.default_address:
                user.default_address = address
                user.save()

        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '新增地址失败!'})

        address_info = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,

            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,

            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'address': address_info
        })

注意:循环调用问题。

===============================

展示地址前后端逻辑

1. 展示地址接口设计和定义

1.请求方式

选项方案
请求方法

GET
请求地址

/addresses/

2.请求参数

2. 展示地址后端逻辑实现


class AddressView(View):

    def get(self, request):

        user = request.user
        addresses = Address.objects.filter(
            user=user,
            is_deleted=False
        )

        address_list = []
        for address in addresses:
            if address.id != user.default_address_id:

                address_list.append({
                    'id': address.id,
                    'title': address.title,
                    'receiver': address.receiver,
                    'province': address.province.name,
                    'city': address.city.name,
                    'district': address.district.name,
                    'place': address.place,
                    'mobile': address.mobile,
                    'tel': address.tel,
                    'email': address.email
                })
            else:
                address_list.insert(0, {
                    'id': address.id,
                    'title': address.title,
                    'receiver': address.receiver,
                    'province': address.province.name,
                    'city': address.city.name,
                    'district': address.district.name,
                    'place': address.place,
                    'mobile': address.mobile,
                    'tel': address.tel,
                    'email': address.email
                })

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'default_address_id': user.default_address_id,
            'addresses': address_list
        })

========================

修改地址前后端逻辑

1. 修改地址接口设计和定义

1.请求方式

选项方案
请求方法

delete、PUT
请求地址

/addresses/(?P

2.请求参数:路径参数 和 JSON

参数名类型是否必传说明
address_id

string是要修改的地址ID(路径参数)
receiver

string是收货人
province_id

string是省份ID
city_id

string是城市ID
district_id

string是区县ID
place

string是收货地址
mobile

string是手机号
tel

string否固定电话
email

string否邮箱

3.响应结果:JSON

字段说明
code

状态码
errmsg

错误信息
id

地址ID
receiver

收货人
province

省份名称
city

城市名称
district

区县名称
place

收货地址
mobile

手机号
tel

固定电话
email

邮箱

2. 修改地址后端逻辑实现

提示

  • 删除地址后端逻辑和新增地址后端逻辑非常的相似。
  • 都是更新用户地址模型类,需要保存用户地址信息。

class UpdateDestroyAddressView(View):

    def delete(self, request, address_id):

        try:
            address = Address.objects.get(pk=address_id)
        except Address.DoesNotExist as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '地址不存在'}, status=404)

        address.is_deleted = True
        address.save()

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok'
        })

    def put(self, request, address_id):

        try:
            address = Address.objects.get(pk=address_id)
        except Address.DoesNotExist as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '资源未找到!'})

        data = json.loads(request.body.decode())
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({"code": 400, 'errmsg': '缺少参数!'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'errmsg': '参数mobile有误'})
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return JsonResponse({'code': 400,
                                     'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400,
                                     'errmsg': '参数email有误'})

        address.receiver = receiver
        address.province_id = province_id
        address.city_id = city_id
        address.district_id = district_id
        address.place = place
        address.mobile = mobile
        address.tel = tel
        address.email = email
        address.save()

        address_info = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,

            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,

            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'address': address_info
        })

================================

设置默认地址

1. 设置默认地址接口设计和定义

1.请求方式

选项方案
请求方法

PUT
请求地址

/addresses/(?P

2.请求参数:路径参数

参数名类型是否必传说明
address_id

string是要修改的地址ID(路径参数)

3.响应结果:JSON

字段说明
code

状态码
errmsg

错误信息

2. 设置默认地址后端逻辑实现


class DefaultAddressView(View):

    def put(self, request, address_id):

        user = request.user

        user.default_address_id = address_id

        user.save()

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok'
        })

==========================

修改地址标题

1. 修改地址标题接口设计和定义

1.请求方式

选项方案
请求方法

PUT
请求地址

/addresses/(?P

2.请求参数:路径参数

参数名类型是否必传说明
address_id

string是要修改的地址ID(路径参数)

3.响应结果:JSON

字段说明
code

状态码
errmsg

错误信息

2. 修改地址标题后端逻辑实现


class UpdateTitleAddressView(View):

    def put(self, request, address_id):

        data = json.loads(request.body.decode())
        title = data.get('title')

        address = Address.objects.get(pk=address_id)

        address.title = title
        address.save()

        return JsonResponse({'code': 0, 'errmsg': 'ok'})

==============================

修改密码

1. 修改密码后端逻辑

提示:

  • 修改密码前需要校验原始密码是否正确,以校验修改密码的用户身份。
  • 如果原始密码正确,再将新的密码赋值给用户。

class ChangePasswordView(View):

    def put(self, request):

        data = json.loads(request.body.decode())
        old_password = data.get('old_password')
        new_password = data.get('new_password')
        new_password2 = data.get('new_password2')

        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code':400, 'errmsg': '参数缺失'})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400,
                             'errmsg': '密码最少8位,最长20位'})

        if new_password != new_password2:
            return JsonResponse({'code': 400,
                             'errmsg': '两次输入密码不一致'})

        user = request.user
        if not user.check_password(old_password):
            return JsonResponse({'code': 400, 'errmsg': '旧密码有误!'}, status=400)

        user.set_password(new_password)
        user.save()

        logout(request)

        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.delete_cookie('username')
        return response

========================

补全users.urls.py中的urlpatterns:


    re_path(r'^addresses/create/$', CreateAddressView.as_view()),

    re_path(r'^addresses/$', AddressView.as_view()),

    re_path(r'^addresses/(?P\d+)/$', UpdateDestroyAddressView.as_view()),

    re_path(r'^addresses/(?P\d+)/default/$', DefaultAddressView.as_view()),

    re_path(r'^addresses/(?P\d+)/title/$', UpdateTitleAddressView.as_view()),

    re_path(r'^password/$', ChangePasswordView.as_view()),

替换user_center_site.js(其中有2个链接接口不对,一个参数,后端未做处理)

========================

开源web框架django知识总结(十三)

祝大家学习python顺利!

Original: https://blog.csdn.net/weixin_54733110/article/details/121913293
Author: 主打Python
Title: 开源web框架django知识总结(十三)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/737467/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 12. Python3 使用matplotlib绘制图表

    matplotlib 是一个数学绘图库, 可用来制作简单的图表, 如折线图和散点图等等. mac pip3 install –user matplotlib -i https:/…

    Python 2023年9月2日
    061
  • Scrapy学习

    scrapy入门 1.scrapy简介 Scrapy是一个基于 Twisted的异步处理框架,是纯python实现的爬虫框架。使用少量代码就能快速抓取数据。Scrapy是适用于Py…

    Python 2023年10月2日
    052
  • 7 天找个 Go 工作,Gopher 要学的条件语句,循环语句 ,第3篇

    本篇博客重点内容 来到 Go 语言学习的第 3 篇博客,本篇将涉及两种 Go 语句,其一是分支,即条件判断,其二是循环。 条件判断语句又细分为 if 语句,if else 语句,i…

    Python 2023年5月24日
    082
  • 基于flask,简单的http文件服务器,提供文件下载服务、文件上传服务

    简单的文件服务器,提供文件下载服务、文件上传服务。 启动:         启动前新建两个目录,和程序同级。download、files Windows系统启动方式有两种: 第2种…

    Python 2023年8月13日
    064
  • 天气/气象相关公开数据集

    ​ 全国气象数据集 2000-2010年 背景描述 包含气温、气压、露点、风向风速、云量、降水量数据 数据说明 时间精度:近年的数据大多为3小时数据,少量站点有1小时数据。 站点数…

    Python 2023年8月2日
    062
  • scrapy学习-第一天

    scrapy学习案例 文章目录 前言 一、scrapy创建项目 二、代码部分 * 1.爬取数据 2.保存图片到本地 3.完整代码 前言 Scrapy 是一个快速高级网络爬行和Web…

    Python 2023年10月7日
    051
  • python的lambda表达式详细讲解

    前言: 作者:神的孩子在歌唱大家好,我叫智 Lambda 表达式是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象,是一个匿名函数,即没有 …

    Python 2023年8月2日
    049
  • pytest_runtest_makereport钩子函数获取测试用例执行结果

    前言 pytest测试框架提供的很多钩子函数方便我们对测试框架进行二次开发,可以根据自己的需求进行改造。 例如:钩子方法: pytest_runtest_makereport ,可…

    Python 2023年9月12日
    042
  • 数学建模——熵权法步骤及程序详解

    数学建模——熵权法步骤及程序详解 权重的求解一直都是数学建模的重点关注对象,所以学好建模论文的重要一步就是如何确定权重,今天是来介绍一种客观确定几个指标各自所占的权重的方法——熵权…

    Python 2023年10月9日
    0148
  • 阿里云部署Flask项目

    一、Mac环境用Royal TSX连接阿里云 Royal TSX,Mac上强力的远程连接管理神器 安装 直接去官网下载即可:www.royalapps.com/ts/win/dow…

    Python 2023年8月12日
    074
  • plt.函数

    1 plt.figure () :创建画布 plt.figure(num=None, figsize=None, facecolor=None, edgecolor=None, c…

    Python 2023年9月30日
    035
  • 20220522Python3.10安装教程

    目录 一、python3.10下载 1.从官网进入Windows python下载页面 2.双击安装python,安装界面勾选Add Python 3.10 to PATH让pyt…

    Python 2023年8月2日
    087
  • 【pytest-html】深度探索pytest-html测试报告的自定义使用

    文章目录 一、前言 二、安装 * 依赖 直接安装 从源码安装 三、基本使用 四、深度使用 * 1. 改变报告样式 示例 2. 修改报告标题 – 示例 3. 修改Envi…

    Python 2023年9月10日
    061
  • 一文读懂CPU工作原理、程序是如何在单片机内执行的、指令格式之操作码地址码

    文章较长,大家可选择性阅读,嘎嘎细 计算机结构 ; CPU的运行原理 CPU的控制单元在时序脉冲的作用下,将指令计数器里所指向的指令地址(这个地址是在内存里的)送到地址总线上去,然…

    Python 2023年11月9日
    079
  • vue+flask遇到的一些问题

    最近写了一个地图网站,前端从githup上拷贝一个很简单的前端模板的下来,可以帮我节约写陆游的配置和一些公用代码。不过还遗憾模板在githup上的地址找不到了。 还是先说回遇到的问…

    Python 2023年8月11日
    055
  • 皮尔逊相关系数python实现

    一、皮尔逊相关系数 常见公式:公式转换:具体和皮尔逊相关系数相关的内容可以看之前的一篇文章。相似度计算(2)——皮尔逊相关系数 ; 二、python实现 方法1:直接按公式算 im…

    Python 2023年8月23日
    049
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球