10.1 Django 框架

1. 几个主流的框架

  • 适合初学者的接口框架:Django,Flask
  • 针对底层定义:Twisted
  • 实现高并发:Tornado

2. 一般web框架的架构模型

Python 全栈测试开发 Chapter10:接口的设计与开发_字段

说明:

  • 首先浏览器给Web服务器发送HTTP请求。
  • 服务器接收到请求后解析请求,然后发送给Web后端框架,web服务器实际主要就是通过WSGI网关通讯服务完成与web框架的交互。
  • 后端框架接收到请求后进行处理(如封装js、数据库交互、业务处理等操作)。
  • 处理结束后把HTTP的响应对象返回给服务器。
  • 服务器把接收到的HTTP响应对象报文最后返回给浏览器。6.最终浏览器将页面进行渲染给用户。

web框架意义: 用于搭建Web应用程序 避免代码重复编写,只需要关心Web应用核心的业务逻辑实现

3. 安装

// 使用python 下的 pip
pip install django
//查看当前Django版本
python3 -m django --version

10.2 框架认识

参考:https://mp.weixin.qq.com/s?__biz=MzI4MzcwMjQxMg==&mid=2247484957&idx=1&sn=852f3c64936dc154817ef64a1cd8a202&chksm=eb87e3fedcf06ae861b37537b993519b8541376caa5d401d10fcc57dc8bbd72b28a4f04c3a8e&scene=21#wechat_redirect

1 django 原理

1)传统三层架构:UIL 表示层(数据的传递和显示操作)、BLL 业务逻辑层(业务逻辑处理)、DAL 数据访问层(数据信息存储及提取),三层中使用的数据,是通过实体类(封装数据的JavaBean)来传递的。实体类一般放在entity包下。

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_02

2)MVC 三层架构

  • Model 模型(对数据库层的访问进行封装)
  • View 视图(将结果封装成页面展示给用户)
  • Controller 控制(实现接受请求,完成请求的业务逻辑处理)

Spring MVC 基本架构:https://www.cnblogs.com/bruce-he/p/13081494.html

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_03

3)Django 的MVT 分层模式(model view template)模块模型视图层;主要是基于 MVC 三层架构而来

  • M:负责与数据库交互,对应 MVC\M,
  • V:接受请求、业务进行处理并进行响应,对应 MVC\C
  • T:构建 HTML,CSS,JS 等,对应 MVC\V

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_04

2 Django概述

1)View 视图层:有两种表现形式:

  • FBV (Function Base View) 函数视图:声明一个函数,其第一个参数必须是 request,即获取当前的请求对象即 httpRequest
  • CBV (Class Base View) 类视图: 声明一个类,该类必须继承 View 对象;在 url 映射的时候,一定要调用 as_view() 方法,且该类中声明的处理方法即是请求方法(方法名必须是 get, post, put...)

响应的处理形式有:

  • 1)数据格式(json)
  • 2)html 页面
  • 3)重定向到 url(需要在 settings.py 的 TEMPLATES \ DIRS 里面 配置 Templates)

10.3 sqlite3介绍

1 sqlite3概述:以文件形式进行存储数据的小型实用的数据库。一般以 .db 或 .sqlite 为后缀

2 下载安装:通过官网进行下载:https://www.sqlite.org/download.html

3 sqlite 运行

1)如已配置了 android sdk 环境变量则可以直接运行 sqlte3 进入

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_05


2)配置到环境变量 PATH 中

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_06

4 sqlite 常见命令#注意:

1)数据库 或 表等操作 命令前加 “.” 2)增删改查等不需要

# 进入 sqlite3
> sqlite3

# 创建 database
1)方式一(cmd 窗口):
> sqlite3 my.db
2)方式二(sqlite 内部):
sqlite> .open my.db

# 查看 database
sqlite> .databases

# 创建表
sqlite> create table userInfo( userID int, userName varchar(20), userPwd varchar(20));

# 查看表
sqlite> .table

#查看表结构
sqlite> .dump

#查看表结构
sqlite> .dump table_name

#查看所有表的创建语句
sqlite>.schema

#查看指定表的创建语句:
sqlite>.schema table_name

# 设置每一列的显示宽度:
sqlite>.width width_value
#例如:设置宽度为2
sqlite>.width 2


# 插入数据
sqlite> insert into userInfo values(1, "admin", "123456");

# 查询数据
sqlite> select * from userInfo;

# 更新数据
sqlite> update userInfo set userPwd = "234567" where userName ="admin";

# 删除数据
sqlite> delete from userInfo where userName = "admin";

# 退出
sqlite> .q

10.4 Django模型层介绍

10.4.1 ORM概述

ORM概念: 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

ORM作用:ORM在业务逻辑层和数据库层之间充当了桥梁的作用。

ORM优点:不用直接编写sql语句,只需要操作对象一样从数据库中操作数据,那么开发人员只需要考虑业务逻辑的处理,从而提高了开发效率。

ORM缺点:在一定程度上会牺牲程序的执行效率以及sql语句技能的退化

10.4.2 Django中ORM的使用

1 在Django项目的settings.py文件中,配置数据库连接信息:

Python 全栈测试开发 Chapter10:接口的设计与开发_django_07

**注意:**mysql数据库在模型层中是不能够自动创建对应的数据库哦,所以此处必须手动在mysql服务器上手动创建一个数据库名叫mydatabase,不然的话后面实现数据迁移和同步的时候会提示无法找到对应的数据库哦

2 在模型层中即models.py文件中声明类,该类对应数据库的表,具体实现如下:

from django.db import models
#创建一个用户信息表
#如果你需要将当前类映射到指定数据库完成对应表结构的创建的话,那么当前类必须继承models.Modle,否则的无法生成迁移文,那么就无法实现数据同步操作
#就相当于是一个普通类
class  CustomerInfo(models.Model):
    #声明客户类型的选择:
    customer_chocie=[("A","A类客户"),("B","B类客户"),("C","C类客户")]
    #例如:将数据导出到execl等文件中,首行都是每列的描述verbose_name;如果不想自动让django默认添加一个id的字段,那么可以自定义id,并将该id的值
    # 设置为主键,那么默认的就不存在,如果不想自定义id的话也不想要自动生成的那个id,那么在当前表中指定一个字段为主键
    #customer_name就是一个主键
    customer_name=models.CharField(max_length=12,name="cus_name",verbose_name="客户名称",primary_key=True)
    customer_type=models.CharField(max_length=2,choices=customer_chocie,name="cus_type")
    #如果是使用integerField的话则不需要声明其长度
    customer_phone=models.IntegerField()
    customer_email=models.CharField(max_length=20)
    customer_address=models.CharField(max_length=100,null=True)

3.定义了modle模型层内容后,则需要实现生成数据迁移文件操作;

使用命令:python manage.py makemigrations apps的名字

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_08

注意:

a.创建好的apps必须要添加到settings中的INSTALLED_APPS,如果不进行配置的话,则会提示无法找到对应的apps。

b.需要安装mysqlclient第三方包,否则提示mysqldb的error错误;

c.最新的django3.0版本无法兼容mysql5.5,需要升级mysql版本或者降级django版本。

其中mysql5.5与mysql最新版本8.0想要同时共存的话,详细操作可以看之前推送的文章 Win10下mysql5.5和mysql8.0.20共存

4.完成数据迁移以及同步数据的操作

命令:python manage.py migrate apps的名字

上面操作完毕后,会在mysql指定配置的数据库中创建所设定模型层的表结构,如下图:

Python 全栈测试开发 Chapter10:接口的设计与开发_django_09

10.4.3 Django模型层应用

上面已经完成了表结构的创建,如果我要对该表完成数据的插入、修改、删除等操作的话,则如何实现?首先操作模型层有两种方式:

1 通过django的请求响应的形式完成数据的操作

from django.http import HttpResponse
from AddCustomer.models import CustomerInfo
def add_customer(request):
    #从页面上获取的数据,传入的参数
    get_info={
    "cus_name":request.GET.get("customer_name"),
    "cus_type":request.GET.get("customer_type"),
    "customer_phone":request.GET.get("customer_phone"),
    "customer_email":request.GET.get("customer_email"),
    "customer_address":request.GET.get("customer_address")
    }
    #前面可以实现一个一个赋值操作
    customer=CustomerInfo.objects.create(**get_info)
    return  HttpResponse("新增客户成功")

上面的代码就是通过请求获取到相应的参数,然后将数据插入到表中,完成客户新增的操作。

2 通过python的main方法直接执行完成操作

必须先配置DJANGO_SETTINGS_MODULE的环境变量,其值是对应django项目的settings环境变量的配置有三种方式:

第一种:针对当前的文件的configurations设置添加

Python 全栈测试开发 Chapter10:接口的设计与开发_django_10

第二种:通过代码的形式完成添加

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE","InterfaceProgram.settings")

但是此种方式的代码必须在django完成初始化的时候进行添加

第三种:上面两种都是局部的,针对当前文件,可以将DJANGO_SETTINGS_MODULE变量直接配置到计算机中

注意:配置完成后,pycharm记得重启

 并且,在操作模型层之前必须先完成django进程初始化操作,否则的话,会抛出异常(AppRegistryNotReady),那么需要在导入模型层模块之前先使用下面语句:

import django
django.setup()

例如:具体实现代码如下:

#-*- coding:utf-8 -*-#
#-------------------------------------------------------------------------
#ProjectName:       Python2020
#FileName:          Insert_Data.py
#Author:            mutou
#Date:              2020/7/14 20:44
#Description:
#--------------------------------------------------------------------------
#实现模型层的数据插入操作:
#环境变量的操作:必须声明在django初始化之前
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE","InterfaceProgram.settings")

import django
django.setup()

from TestOrm.models import UserInfo
if __name__ == '__main__':
    user=UserInfo()
    user.username="zhangsan"
    user.password='1234456'
    user.save()

以上都是实现模型层操作的核心配置,配置很重要哦,少一个或者错误一个都可能会失败的。

10.4.4 Django中的Modle

在Django中model是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。通常,一个模型(model)映射到一个数据库表,基本情况:

  • 每个模型都是一个Python类,它是django.db.models.Model的子类。
  • 模型的每个属性都代表一个数据库字段。
  • 综上所述,Django为您提供了一个自动生成的数据库访问API,详情官网api:https://docs.djangoproject.com/en/3.0/topics/db/models/

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_11

10.4.5 Django字段说明

1 常用字段

  • AutoField:int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
  • IntegerField:一个整数类型,范围在 -2147483648 to 2147483647。
  • CharField:字符类型,必须提供max_length参数, max_length表示字符长度。
  • DateField:日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
  • DateTimeField:日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。

2 字段参数

  • null:用于表示某个字段可以为空。
  • unique:如果设置为unique=True 则该字段在此表中必须是唯一的 。
  • db_index:如果db_index=True 则代表着为此字段设置数据库索引。
  • default:为该字段设置默认值。

3 时间字段独有

DatetimeField、DateField、TimeField这个三个时间字段,都可以设置如下属性。
  • auto_now_add:配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
  • auto_now:配置上auto_now=True,每次更新数据记录的时候会更新该字段。

4 关系字段

ForeignKey外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

  • to:设置要关联的表
  • to_field:设置要关联的表的字段
  • related_name:反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。

例如:

class Classes(models.Model):
    name = models.CharField(max_length=32)

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes")

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().student_set.all()

当我们在ForeignKey字段中添加了参数 related_name 后,

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes", related_name="students")

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().students.all()

  • related_query_name:反向查询操作时,使用的连接前缀,用于替换表名。
  • on_delete:当删除关联表中的数据时,当前表与其关联的行的行为。
  • models.CASCADE:删除关联数据,与之关联也删除
  • models.DO_NOTHING:删除关联数据,引发错误IntegrityError
  • models.PROTECT:删除关联数据,引发错误ProtectedError
  • models.SET_NULL:删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
  • models.SET_DEFAULT:删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
  • models.SET:删除关联数据,(1)与之关联的值设置为指定值,设置:models.SET(值);(2)与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

10.4.6 插入数据

# 法1:直接通过实例化对象来操作,但是需要save()
  obj = Student(name="wood",age=22)
  obj.save()
  
# 法2:通过实例化一个空对象然后增加属性值来操作,但是需要save()
  obj = Student()
  obj.name='wood'
  obj.age=22
  obj.save()
  
# 法3:直接create创建,不需要save()
  # 3.1 方法
    data = {
      name='wood',
      age=22
    }
    Student.objects.create(**data)
  # 3.2 方法
    Student.objects.create(name='wood',age=22)
    
# 法4:通过get_or_create来创建,有则查,无则增
  Student.objects.get_or_create(name='wood',age=22)

10.4.7 修改数据

# 1 单条数据修改
  obj = Student()
  obj.name='wood'
  obj.save()
# 2 整体修改
  Student.objects.filter(条件).update(**data)

10.4.8 删除数据

# 1. 删单条
Student.objects.get(条件).delete()
# 2. 删多条
Student.objects.filter(条件).delete()
Student.objects.all().delete()

10.4.9 查询操作

#一个通过字段获取对应的数据,一个完成查询的基本操作QuerySet
import django
django.setup()

from AddCustomer_2.models import CustomerInfo_2
from django.apps import apps
#from django.db.models import fields
from django.db.models import Count
from django.db.models import F,Q

if __name__ == '__main__':
    #需要获取指定模型层字段中的属性信息
    #通过apps获取模型层对象,以及获取到fields对象
    get_model_object=apps.get_model("AddCustomer_2","CustomerInfo_2")
    
    #如果模型调用所规定的私有属性_meta,在调用对应的fields属性即可获取到fields对象
    get_fields=get_model_object._meta.fields
    for field in get_fields:
        #print(field.verbose_name)
        print(field.name)
        #print(field.max_length)
        
    #聚合统计
    print("数据库总条数:",CustomerInfo_2.objects.all().count())
    print(CustomerInfo_2.objects.aggregate(Count("id")))
    
    #分组统计
    print({value["customer_type"]:value["type_count"] for value in CustomerInfo_2.objects.values("customer_type").annotate(type_count=Count("customer_type"))})
    print(CustomerInfo_2.objects.values("customer_type").annotate(type_count=Count("customer_type")).values("customer_type","type_count"))
   
    #取最后一条记录:last(),可以将id倒序,然后再取第一条
    print(CustomerInfo_2.objects.order_by("-id").first().customer_name)
    print(CustomerInfo_2.objects.order_by("-id").values()[0])
    
    #查询:模糊查询,会与Q对象、F对象进行共同使用
    #Q对象:用于查询时条件之间的逻辑关系,其应用使用not、and、or,也可以使用&  |  ~操作
    #F对象:处理类属性(即模型层的某个列数据),实现的是类属性之间的比较   F("ID")
    get_object=CustomerInfo_2.objects.filter(customer_name="woodtest")
    get_object.update(customer_phone=F("customer_phone")+10)
    #get_object.update(id=F("id")+2)  #update  table   set  id=id+2
    
    #select  *  from  表名  where  id>2   gt  gte   lt   lte  in  startswith endswith contans exact等
    #要查询出id大于2的且客户类型是B类的
    #select  *  form  表名  where  id>2  and customer_type="B"
    #select * from (select * from 表名  where id>2) where customer_type='B'
    #print(CustomerInfo_2.objects.filter(id__gt=2,customer_type__exact='B'))
    
    print(CustomerInfo_2.objects.filter(Q(id__gt=2)|Q(customer_type__exact='B')).values())
    print(CustomerInfo_2.objects.filter(~Q(id=3)).values())
    print(CustomerInfo_2.objects.filter(id__lte=2).filter(customer_name__startswith='w').values())

10.4.10 附录:字段合集

AutoField(Field)
        - int自增列,必须填入参数 primary_key=True
        
    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型

10.4.11 查询字段常用方法

方法                 返回数据类型        作用
  模型类.objects.all()          QuerySet      返回表中所有数据
    
  模型类.objects.filter(xx)      QuerySet      返回符合条件的数据
    
  模型类.objects.exclude(xx="")    QuerySet      返回不符合条件的数据
    
  模型类.objects.order_by("")      QuerySet      对查询结果集进行排序  -为反序,不加-为正序      #里面要对字段用""包起来才行
    
  模型类.objects.values()        QuerySet      返回一个QuerySet 每个元素为一个字典
    
  模型类.objects.order_by("").reverse()  QuerySet    对排序的结果反转         #结合order_by来使用
    
  模型类.objects.get()          模型对象        返回一个满足条件的对象;
                              如果没有找到符合条件的对象,会引发     模型类.DoesNotExist异常; 
                              如果找到多个,会引发模型类.MultiObjectsReturned 异常
                              
  模型类.objects.count()        int          返回查询集中对象的数目
    
  模型类.objects.first()        模型对象        返回第一条数据
    
  模型类.objects.last()        模型对象        返回最后一条数据
    
  模型类.objects.exists()        bool        判断查询的数据是否存在
   
  模型类.object.values_list("x","xx") QuerySet        返回一个QuerySet 每个元素为一个元组

  模型类.objects.only("")        QuerySet      返回一个QuerySet 每个元素为一个对象,同时其他字段也能拿到
    
  模型类.objects.defer("")        QuerySet      返回一个QuerySet 返回不符合条件的字段
    
  and  模型类.objects.filter(条件1,条件2)  QuerySet    返回一个QuerySet 每个元素为一个对象
    
  or  需要导入 from django.db.models import Q 
    模型类.objects.filter(Q(条件1)|Q(条件2))  QuerySet  返回一个QuerySet 每个元素为一个对象
    
  查询条件
      
  模型类.objects.filter(字段名__exact = "")  准确匹配,区分大小写
    
  模型类.objects.filter(字段名__iexact = "")  匹配,不区分大小写
    
  模型类.objects.filter(字段名__contans = "x")  字段名里面包含x的都匹配,区分大小写
    
  模型类.objects.filter(字段名__icontans = "x")字段名里面包含x的都匹配,不区分大小写
    
  模型类.objects.filter(字段名__in = [[],""])  指定值查询,可以使列表,可以是字符串,也可以是元组
    
  
  模型类.objects.filter(字段名__gt = "")  大于该数值的数据
    
  模型类.objects.filter(字段名__gte = "")  大于等于该数值的数据
    
  模型类.objects.filter(字段名__lt = "")  小于该数值的数据
    
  模型类.objects.filter(字段名__lte = "")  小于等于该数值的数据
    
  模型类.objects.filter(字段名__range =(a,b))  在这个范围内的数据
  
  聚合函数和分组
    from django.db.models import Count,Avg,Max,Min
    
    模型类.objects.value("字段名A").annotate(新名字=聚合函数名("字段名A"))
    
    __双下划线模糊查询

10.4 Django项目实操1

原文链接:https://blog.csdn.net/ImagineCode/article/details/54586326https://gitcode.csdn.net/65aa2e4eb8e5f01e1e44c566.html?dp_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6NjcxNDM2LCJleHAiOjE3MDk2OTU3ODMsImlhdCI6MTcwOTA5MDk4MywidXNlcm5hbWUiOiJ4aWFvaHVpMzY5NTIxIn0.XaHsP1Tz4J3Kpvu_jsrFIqw_WSFJ-g7lJATs6QIK9Ow

(1) 新建Django项目

可用命令在终端创建project:django-amdin startproject djangotest可用pycharm创建project:如图示

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_12

Python 全栈测试开发 Chapter10:接口的设计与开发_django_13

** Django 项目目录结构**

wsgi.py:   	web 服务,支持 HTTP 协议,但不支持 WebSocket 协议
asgi.py:		web 服务,支持 HTTP + WebSocket 协议,还支持 Web 开发中的一些新标准,是 WSGI 的一种扩展
settings.py:	配置文件,包括 数据库设置、网页语言、环境配置、安全配置、参数配置等
urls.py:		url 路由,可实现 Web 中 url 路径访问的映射操作
manage.py:		django 服务运行及管理的命令管理集合的管理工具。可以与 Django 项目交换,可看作项目的 djiango-admin.py(Python39\Scripts\ 下) 版本,实际上,两者共有相同的后台代码
db.sqllite3:	数据库文件,以文件形式存储的数据格式

settings.py文件详情介绍

import os

# 项目的相对路径,启动服务的时候会运行这个文件所在路径的manage.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 安全密钥
SECRET_KEY = 'l&!v_npes(!j82+x(44vt+h&#ag7io2x&shnf*9^8fv0d63!0r'

# 是否开启Debug
DEBUG = True

# 允许访问的主机ip,可以用通配符*
ALLOWED_HOSTS = []

# Application definition

# 用来注册App 前6个是django自带的应用
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

# 中间件 ,需要加载的中间件。比如在请求前和响应后根据规则去执行某些代码的方法
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# 指定URL列表文件 父级URL配置
ROOT_URLCONF = 'djangoDemo.urls'

# 加载网页模板路径
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# WSGI的配置文件路径
WSGI_APPLICATION = 'djangoDemo.wsgi.application'

# 数据库配置 默认的数据库为sqlite
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# 相关密码验证
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# 语言设置 默认英语, 中文是zh-hans
LANGUAGE_CODE = 'en-us'

# 时区设置,中国的是:Asia/Shanghai
TIME_ZONE = 'UTC'

# i18n字符集是否支持
USE_I18N = True

USE_L10N = True

# 是否使用timezone
# 保证存储到数据库中的是 UTC 时间;
# 在函数之间传递时间参数时,确保时间已经转换成 UTC 时间;
USE_TZ = True

# 静态文件路径
STATIC_URL = '/static/'

(2) 创建APP

在每个django项目中可以包含多个APP,相当于一个大型项目中的分系统、子模块、功能部件等等,相互之间比较独立,但也有联系。所有的APP共享项目资源。举个例子我们需要开发一个电商网站,那么产品列表、购物车、下单等等这都是不同的业务线,我们可以把每条业务线都看做一个App。  在pycharm下方的terminal终端中输入命令:python manage.py startapp fxhtest  这样就创建了一个叫做fxhtest的APP,django自动生成“fxhtest”文件夹。

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_14

**app_demo目录结构**

admin:	对应应用后台管理配置文件
apps:	对应应用的配置文件
models:	数据模块,用于设计数据库等
tests:	编写测试脚本
views:	视图层,直接和浏览器进行交互

(3) 编写路由urls.py

路由都在urls文件里,它将浏览器输入的url映射到相应的业务处理逻辑。  简单的urls编写方法如下图:

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_15

from django.contrib import admin
from django.urls import path
from fxhtest import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path("index/", views.index),
]

重要说明

#是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
#该内容在你安装的pythonsite-packages目录下,例如:C:\Users\zemuerqi\PycharmProjects\Python2020\venv\Lib\site-packages\django\conf\global_settings.py
APPEND_SLASH=True

(4) 编写业务处理逻辑views.py

业务处理逻辑都在views.py文件里。  """

django.http模块中定义了HttpResponse 对象的API 作用:不需要调用模板直接返回数据 HttpResponse属性: content: 返回内容,字符串类型 charset: 响应的编码字符集 status_code: HTTP响应的状态码 """

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_16

函数视图和类试图的区别:https://blog.csdn.net/qq_41341757/article/details/108219754

#函数视图
from django.shortcuts import render

# Create your views here.
user_list = [
    {"user": "jack", "pwd": "abc"},
    {"user": "tom", "pwd": "ABC"},
    {"user": "xxx", "pwd": "111"},
    {"user": "yyyy", "pwd": "222"},
]


def index(request):
    # return HttpResponse("hello world")  #返回http响应
    # return redirect("http://www.baidu.com")  #重定向url地址
    if request.method == "post":
        username = request.POST.get("username", None)
        password = request.POST.get("password", None)
        print(username, password)
        temp = {"user": username, "pwd": password}
        user_list.append(temp)
    return render(request, "index.html", {"data": user_list})#重定向到index.html页面

# get接口
def getRequestTest(request):
    if request.method == "GET":
        username = request.GET.get("username")
        return HttpResponse(username)
    else:
        return render(request, "index.html")


# post接口
def postRequestTest(request):
    if request.method == "POST":
        username = request.POST.get("username")
        return HttpResponse(username)
    else:
        return render(request, "index.html")
#类视图
###urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path("LoginClass",LoginClass.as_view()),
]

####views.py
from django.http import HttpResponse
from django.shortcuts import redirect, render, render_to_response
from django.views import View
class LoginClass(View):
    # get接口
    def get(self,request):
        if self.method == "GET":
            username = self.GET.get("username")
            return HttpResponse(username)
        else:
            return render(self, "index.html")

    # post接口
    def post(self,request):
        if request.method == "POST":
            username = request.POST.get("username")
            return HttpResponse(username)
        else:
            return render(request, "index.html")

通过上面两个步骤,我们将index这个url指向了views里的index()函数,它接收用户请求,并返回一个“hello world”字符串。

(5) 启动 Django 服务

1 命令行启动
// 在 Django project 的 manage.py 目录下,运行,
python manage.py runserver

访问 http://127.0.0.1:8000/,提示 successful 就表示服务启动成功

Python 全栈测试开发 Chapter10:接口的设计与开发_django_17

2 指定 IP 及 端口,可以让其他人访问
python manage.py runserver 172.17.2.15:30060

浏览器访问时 http://172.17.2.15:30060/

注意:

a.上面命令表示的是启动django服务,使用的是环回地址以及默认的端口号,如果需要自定义ip和端口号的话则可以直接在runserver后面添加ip地址:端口号

b.端口号不能够被占用,不能够使用浏览器(限制的端口不同,例如:chrome:6666)所认为的不安全端口

c.如果使用ip地址进行报错:allowed_hosts的话,

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_18

=> 依据提示,修改 提示目录下的 request.py,将 IP 地址添加到 allowed_hosts 中,完成后,再次刷新,就可以正常访问了。

Python 全栈测试开发 Chapter10:接口的设计与开发_django_19

3 服务启动(pycharm 运行 manage.py

1)pycharm 右键 manage.py,run manage.py,会提示 “Type 'manage.py help ' for help on a specific subcommand.”

Python 全栈测试开发 Chapter10:接口的设计与开发_django_20

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_21

2)点击右边的 manage -> Edit Configuation -> 修改 Parameters,新增 “runserver 192.168.1.6:30060” -> 回到 manage.py,再右键 run manage,这次可以正常启动了

Python 全栈测试开发 Chapter10:接口的设计与开发_django_22

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_23

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/4c5b12e3bf0340c584a0bd7b101f6809.png

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_24

(6) 返回HTML文件

上面我们返回给用户浏览器的是什么?一个字符串!实际上这肯定不行,通常我们都是将html文件返回给用户。 下面,我们写这么一个index.html文件:

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_25

 再修改一下views文件:

Python 全栈测试开发 Chapter10:接口的设计与开发_django_26

为了让django知道我们的html文件在哪里,需要修改settings文件的相应内容。但默认情况下,它正好适用,你无需修改。

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_27

接下来,我们可以重新启动web服务。在浏览器刷新一下,你会看到带有样式的“hello world”。

注:这里有个小技巧,在多次频繁重启服务时,由于端口未释放的原因,容易启动不了服务,修改一下端口就OK了。

(7) 使用静态文件

我们已经可以将html文件返还给用户了,但是还不够,前端三大块,html、css、js还有各种插件,它们齐全才是一个完整的页面。在django中,一般将静态文件放在static目录中。接下来,在mysite中新建个static目录。CSS,JS和各种插件都可以放置在这个目录里。

Python 全栈测试开发 Chapter10:接口的设计与开发_django_28

为了让django找到这个目录,依然需要对settings进行配置:

Python 全栈测试开发 Chapter10:接口的设计与开发_django_29

同样,在index.html文件中,可以引入js文件了:

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_30

重新启动web服务,刷新浏览器,查看结果。

(8) 接收用户发送的数据

上面,我们将一个要素齐全的html文件返还给了用户浏览器。但这还不够,因为web服务器和用户之间没有动态交互。

下面我们设计一个表单,让用户输入用户名和密码,提交给index这个url,服务器将接收到这些数据。

先修改index.html文件

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_31

然后修改views.py文件

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_32

**问题:**此时 ,重启web服务时,如果是post请求,在请求过程中出现403forbidden的话 原因: 因为CSRF 表示django全局发送post请求均需要字符串验证,Django默认开启了CSRF防护,会对非GET请求(POST, PUT, DELETE)进行CSRF防护验证,**功能:**防止跨站请求伪造的功能**工作原理:**客户端访问服务器端,在服务器端正常返回给客户端数据的时候,而外返回给客户端一段字符串,等到客户端下次访问服务器端时,服务器端会到客户端查找先前返回的字符串,如果找到则继续,找不到就拒绝。**解决:**在测试时可以关闭CSRF防护机制,关闭CSRF防护机制(2)是在settings.py文件中注释掉CSRF中间件,(2)如果就是不想注释的话,可以通过修改header,在views打印cookie可以得到csrftoken

Python 全栈测试开发 Chapter10:接口的设计与开发_django_33

def index(request):
    print("cookie",request.COOKIES)
    #cookie {
    # 'csrftoken': 'AB9v1MGTbdpSGg3FaGCIiUxrKVR8zKSqgdGFDn5E0ADsJ2ST7N2zgW6KboQ8G31x',
    # 'sessionid': 'eexw5p38vky9qo38nf372dz5lj1br6xf'
    # }
    #cookie 是浏览器给的,
    return HttpResponse("index")

再次进入浏览器,刷新页面:

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_34

输入点东西,然后我们在pycharm中可以看到相应的数据。

(9) 返回动态页面

我们收到了用户的数据,但返回给用户的依然是个静态页面,通常我们会根据用户的数据,进行处理后在返回给用户。这时候,django采用jinja2语言编写动态模板,jinja2会根据提供的数据,替换掉html中的相应部分,详细语法入门后再深入学习。先改造views.py文件:

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_35

再改造index.html文件:

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_36

重启服务,刷新浏览器:

Python 全栈测试开发 Chapter10:接口的设计与开发_django_37

可以看到,我们获得了用户实时输入的数据,并将它实时展示在了用户页面上,这是个不错的交互过程。

(10) 使用数据库

流程走到这里,django的MTV框架基本已经浮出水面了,只剩下最后的数据库部分了。  上面我们虽然和用户交互得很好,但并没有保存任何数据,页面一旦关闭,或服务器重启,一切都将回到原始状态。  使用数据库是毫无疑问的,django通过自带的ORM框架操作数据库,并且自带轻量级的sqlite3数据库。下面我们来看一看:  首先是注册app,不注册它,你的数据库就不知道该给哪个app创建表。

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_38

不注册它,你的数据库就不知道该给哪个app创建表。

然后我们在settings中,配置数据库相关的参数,如果使用自带的sqlite,不需要修改。

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_39

再编辑models.py文件,也就是MTV中的M。

Python 全栈测试开发 Chapter10:接口的设计与开发_django_40

这里我们创建了2个字段,分别保存用户的名字和密码。接下来要在pycharm的teminal中通过命令创建数据库的表了。有2条命令,分别是:python manage.py makemigrations

Python 全栈测试开发 Chapter10:接口的设计与开发_django_41

再输入命令:python manage.py migrate

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_42

修改views.py中的业务逻辑

重启web服务后,刷新浏览器页面,之后和用户交互的数据都能保存到数据库中。任何时候都可以从数据库中读取数据,展示到页面上。

至此,一个要素齐全,主体框架展示清晰的django项目完成了,其实很简单是不是?


10.5 Django项目实操2-sqlite3数据库连接,校验登录名和密码

需求:完成设计一个登陆的接口,要求返回一个json格式的响应。分析:在视图层完成登陆请求的用户名和密码的数据库数据校验,然后返回对应的json格式结果。结果可能性:第一:用户名重名,这是个bug需要返回一个状态,数据库中存在两个重名的用户第二:用户名不存在,在数据库中查询不到第三:密码错误 第四:都正确 定义json的格式:"reason": "数据库中存在同名的用户","result": [],"error_code": 2000 "reason": "用户名不存在","result": [],"error_code": 2001 "reason": "密码错误","result": [],"error_code": 2002 "reason": "数据库服务错误","result": [],"error_code": 2003 { "reason": "登陆成功", "result": { username:请求的用户名 password:登陆成功 }, "error_code": 0 / * 登陆成功* / }

新建app Login

Python 全栈测试开发 Chapter10:接口的设计与开发_django_43

(1)修改urls.py文件

#第五步:完成urls路由映射操作

from django.contrib import admin
from django.urls import path
from Login.View.Login_Index import LoginIndexClass,LoginIndex
from Login.View.Login_Check_Action import LoginCheckAction
from Login.View.Login_Action import LoginAction
from AddCustomer.views import add_customer,select_data
from AddCustomer_2.views import add_customer,update_customer,delete_customer,select_customer
from Login.View.views import getRequestTest
from Login.View.views import Login
urlpatterns = [
    #默认的django管理员页面
    path('admin/', admin.site.urls),
    path("loginAction",LoginCheckAction.as_view()), #自定义url路由映射规则

(2)新建数据库my.db

(base) PS E:\learn\C10\InterfaceProgram\Login\Modle> sqlite3
SQLite version 3.36.0 2021-06-18 18:36:39
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open my.db
sqlite> create table userinfo (username varchar(20),password varchar(20));
sqlite> .table
userinfo
sqlite> insert into userinfo values ("zhangsan","123456");
sqlite> insert into userinfo values ("lisi","abc");
sqlite> select * from userinfo;
zhangsan|123456
lsi|abc
sqlite>.q

(3)修改models.py

from django.db import models


# 声明一个类,实现往指定的数据库中创建一个表,通过类与表实现映射关系操作
class UserInfo(models.Model):
    # 声明属性,并定义字段的长度  create  table  UserInfo(username varchar(20) NOT NULL,password varchar(20) NOT NULL)
    # 会默认添加id字段,并且默认设定为主键
    username = models.CharField(max_length=20,primary_key=True)
    password = models.CharField(max_length=20)

(4)修改Conn_Sqlite.py

#第二步:获取数据库中数据

# 该文件完成sqlite数据库中的数据读取操作
# 任何一个数据库操作其主要都是基于链接对象的创建
import sqlite3

from testDjango.settings import BASE_DIR


class ConnSqlite(object):
    def __init__(self):
        print("基本地址", BASE_DIR) # 基本地址 E:\learn\C10\InterfaceProgram
        self.conn = sqlite3.connect(BASE_DIR + "/Login/Model/my.db")
        self.cursor = self.conn.cursor()

    # 读取数据
    def read_data(self, str_sql):
        self.cursor.execute(str_sql)
        get_result = self.cursor.fetchall()
        return get_result


if __name__ == '__main__':
    print(BASE_DIR + "/						Login/Model/my.db")
    conn = ConnSqlite()
    str_sql = "select password from userinfo where username='%s'" % 'zhangsan'
    print(conn.read_data(str_sql))

(5)修改settings.py

执行报错: D:\Anaconda3\python.exe E:\learn\testProject\Login\Modle\Conn_Sqlite.py Traceback (most recent call last): File "E:\learn\testProject\Login\Modle\Conn_Sqlite.py", line 22, in print(BASE_DIR + "Login/Modle/my.db") TypeError: unsupported operand type(s) for +: 'WindowsPath' and 'str' 解决:修改settings.py

"Login"

#BASE_DIR = Path(__file__).resolve().parent.parent
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

        #"DIRS": [BASE_DIR / 'Login/Template'],
        "DIRS":[os.path.join(BASE_DIR,'Login/Template')],
        
        # "NAME": BASE_DIR / "db.sqlite3",
        "NAME": os.path.join(BASE_DIR, "Login/Model/my.db"),

(6)修改Login_Check_Action.py

#该模块完成数据库的校验,从页面上传入的登陆数据实现后台数据库中的数据进行比较校验,如果存在且一致则表示登陆成功,否则登陆失败
from django.views import View
from django.http import HttpResponse
from Login.Module.Conn_Sqlite import ConnSqlite
import json
from TestOrm.models import UserInfo
class  LoginCheckAction(View):
    #根据页面传入的用户名与数据库中的数据进行比较密码、检测用户是否存在
        
   # 第一步:先获取到请求中的用户名和密码数据     
    #先获取到请求中的用户名和密码数据,从页面上获取数据,并封装在一个方法中
    def get_userinfo(self,method_obj):
        #与前端页面进行交互的,同样可以设定默认值,如果前端没有对应的属性时,则取默认值,如果有值则取前端所获取到属性所对应的值
        get_username=method_obj.get("username","wangwu")
        get_password=method_obj.get('password')
        return {"password":get_password,"username":get_username}
      
#获取数据库中数据,此处以django自带的sqlite的数据库为实例:,为了获取数据库连接对象
    def get_database(self,username):
        conn = ConnSqlite()
        str_sql = "select password from userinfo where username='%s'" % username
        return conn.read_data(str_sql)  
    #真正完成页面数据与数据库中数据进行比较的操作
    # 分析:第一:用户名重名,这是个bug需要返回一个状态,数据库中存在两个重名的用户
    # 第二:用户名不存在,在数据库中查询不到
    # 第三:密码错误
    # 第三:都正确
    # 定义json的格式:"reason": "数据库中存在同名的用户","result": [],"error_code": 2000
    # "reason": "用户名不存在","result": [],"error_code": 2001
    # "reason": "密码错误","result": [],"error_code": 2002
    # "reason": "数据库服务错误","result": [],"error_code": 2003
    # {
    #     "reason": "登陆成功",
    #     "result": {
    #                username:
    #                 password:
    # },
    # "error_code": 0 / * 发送成功 * /
    # }
# 第三步:完成从请求中获取的数据与数据库中数据进行对比,
   def compare_data(self, method_obj):
        get_page_info = self.get_userinfo(method_obj)
        get_database_info = self.get_database(get_page_info["username"])
        print("获取的页面信息:", get_page_info)
        return_result = {"reason": [], "result": [], "error_code": []}
        if len(get_database_info) > 1:
            return_result["reason"] = "数据库中存在同名的用户"
            return_result[
                "error_code"] = 2000  # return {"reason": "数据库中存在同名的用户","result": get_page_info,"error_code": 2000}
        elif len(get_database_info) == 0:
            return_result["reason"] = "用户名不存在"
            return_result["error_code"] = 2001  # return {"reason":"用户名不存在","result": get_page_info,"error_code": 2001}
        elif get_database_info[0][0] != get_page_info["password"]:
            return_result["reason"] = "密码错误"
            return_result["error_code"] = 2002  # return {"reason": "密码错误","result": get_page_info,"error_code": 2002}
        else:
            return_result["reason"] = "登陆成功"
            return_result["error_code"] = 0
            return_result[
                "result"] = get_page_info  # return { "reason": "登陆成功","result":get_page_info,"error_code": 0 }
        return return_result

#第四步:通过指定的请求方法将结果响应给客户端,例如,声明get和post方法
    def get(self, request):
        # return HttpResponse(self.get_userinfo(request.GET))
        return HttpResponse(json.dumps(self.compare_data(request.GET), ensure_ascii=False))

    def post(self, request):
        return HttpResponse(json.dumps(self.compare_data(request.POST), ensure_ascii=False))

(7)启动Django和访

启动方式参考【10.4 Django项目实操1 】中的【 (5) 启动 Django 服务】

10.6 Django项目实操3-实现用户名密码登陆后的响应操作

需求:Django对mysql数据库的校验及登录接口的实现

新建app Login和TestOrm,与InterfaceProgram同一目录级别

(1)修改urls.py文件

from django.contrib import admin
from django.urls import path

from Login.View.Login_Action import LoginAction
from Login.View.Login_Check_Action import LoginCheckAction

urlpatterns = [
    path("admin/", admin.site.urls),
    path("insert_data", LoginAction.as_view()), ## 实现用户名密码登陆后的响应操作
]

(2)新建数据库my.db

(base) PS E:\learn\C10\InterfaceProgram\Login\Modle> sqlite3
SQLite version 3.36.0 2021-06-18 18:36:39
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open my.db
sqlite> create table userinfo (username varchar(20),password varchar(20));
sqlite> .table
userinfo
sqlite> insert into userinfo values ("zhangsan","123456");
sqlite> insert into userinfo values ("lisi","abc");
sqlite> select * from userinfo;
zhangsan|123456
lsi|abc
sqlite>.quit

(3)修改Conn_Sqlite.py

# 该文件完成sqlite数据库中的数据读取操作
# 任何一个数据库操作其主要都是基于链接对象的创建
import sqlite3
from InterfaceProgram.settings import BASE_DIR


class ConnSqlite(object):
    def __init__(self):
        print("基本地址", BASE_DIR) # 基本地址 E:\learn\C10\InterfaceProgram
        self.conn = sqlite3.connect(BASE_DIR + "/Login/Modle/my.db")
        self.cursor = self.conn.cursor()

    # 读取数据
    def read_data(self, str_sql):
        self.cursor.execute(str_sql)
        get_result = self.cursor.fetchall()
        return get_result


if __name__ == '__main__':
    print(BASE_DIR + "Login/Modle/my.db")
    conn = ConnSqlite()
    str_sql = "select password from userinfo where username='%s'" % 'zhangsan'
    print(conn.read_data(str_sql))

执行报错: D:\Anaconda3\python.exe E:\learn\testProject\Login\Modle\Conn_Sqlite.py Traceback (most recent call last): File "E:\learn\testProject\Login\Modle\Conn_Sqlite.py", line 22, in print(BASE_DIR + "Login/Modle/my.db") TypeError: unsupported operand type(s) for +: 'WindowsPath' and 'str' 解决:修改settings.py

#BASE_DIR = Path(__file__).resolve().parent.parent
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

        #"DIRS": [BASE_DIR / 'Login/Template'],
        "DIRS":[os.path.join(BASE_DIR,'Login/Template')],
        
        # "NAME": BASE_DIR / "db.sqlite3",
        "NAME": os.path.join(BASE_DIR, "Login/Modle/my.db"),

(4)修改TestOrm/models.py

from django.db import models


# Create your models here.

class UserInfo(models.Model):
    username = models.CharField(max_length=20)
    password = models.CharField(max_length=20)

(5)修改settings.py

执行报错:

apps.populate(settings.INSTALLED_APPS) File "D:\Anaconda3\lib\site-packages\django\apps\registry.py", line 91, in populateapp_config = AppConfig.create(entry)File "D:\Anaconda3\lib\site-packages\django\apps\config.py", line 193, in createimport_module(entry)File "D:\Anaconda3\lib\importlib\init.py", line 127, in import_modulereturn _bootstrap._gcd_import(name[level:], package, level)File "", line 1030, in _gcd_importFile "", line 1007, in _find_and_loadFile "", line 984, in _find_and_load_unlockedModuleNotFoundError: No module named 'LoginTestOrm'

解决:修改settings.py

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_44

"Login",
    "TestOrm",

#BASE_DIR = Path(__file__).resolve().parent.parent
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

        #"DIRS": [BASE_DIR / 'Login/Template'],
        "DIRS":[os.path.join(BASE_DIR,'Login/Template')],
        
        # "NAME": BASE_DIR / "db.sqlite3",
        "NAME": os.path.join(BASE_DIR, "Login/Model/my.db"),

(6)修改Login_Action.py

# -*- coding:utf-8 -*-#
# Login_Action.py
# 实现用户名密码登陆后的响应操作
from django.views import View
from django.http import HttpResponse
import json
from TestOrm.models import UserInfo


class LoginAction(View):
    # 要求返回一个json格式,定义status的状态值可以是success:0和fail:1
    # {status:success,code:0}
    def get(self, request):
        # 成功肯定是需要判定你页面上输入的用户名密码与数据库是否一致,如果一致那么就返回成功状态,如果不一致则返回其他状态
        dict1 = {'status': 'success', 'code': 0}
        # 需要从请求中的页面里面获取对应输入的用户名和密码值,那么必然需要从请求对象中进行获取,
        print("当前请求的协议", request.scheme)
        print("当前请求的方法", request.method)
        print("请求的用户名:", request.GET.get("username"))
        print("请求的密码:", request.GET.get("password"))
        # 设定默认的用户名为:zhangsan   密码:123456  request.GET其返回的对象是一个querydict对象,可以通过get方法指定对应的键名进行获取
        get_username = request.GET.get("username")
        get_password = request.GET.get("password")
        get_info = {"username": get_username, "password": get_password}
        if get_username == "zhangsan" and get_password == '123456':
            dict1.update({"result": get_info})
            return HttpResponse(json.dumps(dict1))
        elif get_username != "zhangsan":
            return HttpResponse(json.dumps({"status": "用户名错误", 'code': 1, "result": get_info}, ensure_ascii=False))
        elif get_username == "zhangsan" and get_password != "123456":
            return HttpResponse(json.dumps({"status": "密码错误", "code": 2, "result": get_info}, ensure_ascii=False))

    # 声明一个post请求
    def post(self, request):
        user = UserInfo()
        user.username = request.POST.get("username")
        user.password = request.POST.get("password")
        user.save()
        return HttpResponse("数据新增成功")  # return HttpResponse(json.dumps({"status":100}))

(7)启动Django即可

启动方式参考【10.4 Django项目实操1 】中的【 (5) 启动 Django 服务】

10.7 Django项目实操3-客户进行增删改查

新建app AddCustomer_2

(1)修改urls.py文件

from django.contrib import admin
from django.urls import path

from AddCustomer.views import select_data
from AddCustomer_2.views import add_customer, select_customer, update_customer, delete_customer
from Login.View.Login_Action import LoginAction
from Login.View.Login_Check_Action import LoginCheckAction

urlpatterns = [
    path("admin/", admin.site.urls),

    path("add_customer", add_customer),
    path('addCustomer', add_customer),
    path('queryCustomer', select_customer),
    path('updateCustomer', update_customer),
    path('deleteCustomer', delete_customer)
]

(2)修改settings.py

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_45

(3)修改AddCustomer_2/views.py

from Public.Get_CustromerInfo import get_customerinfo
from django.http import HttpResponse
from AddCustomer_2.models import CustomerInfo_2
import json
from Public.JudgeMethod import JudgeMethod
from Public.CheckData import Check_Data
from Public.ResponseData import ResponseData
from django.db.models import Count


# 新增客户的接口
def add_customer(request):
    ju = Check_Data(request.POST)
    get_page_info = get_customerinfo(request.POST)
    get_database_info = CustomerInfo_2.objects.filter(customer_name=get_page_info['customer_name'])
    if ju.judge_allpars_notNone():
        if ju.judge_allpars_Null():
            return HttpResponse(json.dumps(ResponseData.get_message_one(), ensure_ascii=False))
        elif len(get_database_info) >= 1:
            return HttpResponse(json.dumps(ResponseData.get_message_two(), ensure_ascii=False))
        elif get_page_info["customer_name"] == '':
            return HttpResponse(json.dumps(ResponseData.get_message_three(), ensure_ascii=False))
        elif len(get_page_info["customer_name"]) < 6 or len(get_page_info["customer_name"]) > 12:
            return HttpResponse(json.dumps(ResponseData.get_message_four(), ensure_ascii=False))
        elif get_page_info["customer_type"] == '':
            return HttpResponse(json.dumps(ResponseData.get_message_five(), ensure_ascii=False))
        elif ju.judge_comseter_type():
            return HttpResponse(json.dumps(ResponseData.get_message_six(), ensure_ascii=False))
        elif get_page_info["customer_phone"] == '':
            return HttpResponse(json.dumps(ResponseData.get_message_seven(), ensure_ascii=False))
        elif len(get_page_info["customer_phone"]) != 11:
            return HttpResponse(json.dumps(ResponseData.get_message_eight(), ensure_ascii=False))
        elif not JudgeMethod.judge_isdigit(get_page_info["customer_phone"]):
            return HttpResponse(json.dumps(ResponseData.get_message_nine(), ensure_ascii=False))
        elif not JudgeMethod.judge_head(get_page_info["customer_phone"]):
            return HttpResponse(json.dumps(ResponseData.get_message_ten(), ensure_ascii=False))
        elif get_page_info["customer_mail"] == '':
            return HttpResponse(json.dumps(ResponseData.get_message_eleven(), ensure_ascii=False))
        elif not JudgeMethod.judge_tail(get_page_info["customer_mail"]):
            return HttpResponse(json.dumps(ResponseData.get_message_twelve(), ensure_ascii=False))
        else:
            CustomerInfo_2.objects.create(**get_page_info)
        return HttpResponse(json.dumps(ResponseData.get_message_seventeen(get_page_info), ensure_ascii=False))
    elif get_page_info["customer_name"] is None:
        return HttpResponse(json.dumps(ResponseData.get_message_thirteen(), ensure_ascii=False))
    elif get_page_info["customer_type"] is None:
        return HttpResponse(json.dumps(ResponseData.get_message_fourteen(), ensure_ascii=False))
    elif get_page_info["customer_phone"] is None:
        return HttpResponse(json.dumps(ResponseData.get_message_fiveteen(), ensure_ascii=False))
    elif get_page_info["customer_mail"] is None:
        return HttpResponse(json.dumps(ResponseData.get_message_sixteen(), ensure_ascii=False))


# 修改客户的接口
def update_customer(request):
    ju = Check_Data(request.POST)
    get_page_info = get_customerinfo(request.POST)
    get_customer_name = CustomerInfo_2.objects.filter(customer_name=get_page_info['customer_name'])
    if get_page_info['customer_name'] is not None:
        if len(get_customer_name) == 1:
            customer = CustomerInfo_2.objects.get(customer_name=get_page_info['customer_name'])
            if get_page_info['customer_type'] is not None:
                if ju.judge_comseter_type():
                    return HttpResponse(json.dumps(ResponseData.get_message_six(), ensure_ascii=False))
                elif get_page_info['customer_type'] == '':
                    return HttpResponse(json.dumps(ResponseData.get_message_five(), ensure_ascii=False))
                else:
                    customer.customer_type = get_page_info['customer_type']
                    customer.save()
                    return HttpResponse(json.dumps(ResponseData.get_message_eighteen(), ensure_ascii=False))
            elif get_page_info['customer_phone'] is not None:
                if get_page_info["customer_phone"] == '':
                    return HttpResponse(json.dumps(ResponseData.get_message_seven(), ensure_ascii=False))
                elif len(get_page_info["customer_phone"]) != 11:
                    return HttpResponse(json.dumps(ResponseData.get_message_eight(), ensure_ascii=False))
                elif not JudgeMethod.judge_isdigit(get_page_info["customer_phone"]):
                    return HttpResponse(json.dumps(ResponseData.get_message_nine(), ensure_ascii=False))
                elif not JudgeMethod.judge_head(get_page_info["customer_phone"]):
                    return HttpResponse(json.dumps(ResponseData.get_message_ten(), ensure_ascii=False))
                else:
                    customer.customer_phone = get_page_info['customer_phone']
                    customer.save()
                    return HttpResponse(json.dumps(ResponseData.get_message_eighteen(), ensure_ascii=False))
            elif get_page_info['customer_mail'] is not None:
                if get_page_info["customer_mail"] == '':
                    return HttpResponse(json.dumps(ResponseData.get_message_eleven(), ensure_ascii=False))
                elif not JudgeMethod.judge_tail(get_page_info["customer_mail"]):
                    return HttpResponse(json.dumps(ResponseData.get_message_twelve(), ensure_ascii=False))
                else:
                    customer.customer_mail = get_page_info['customer_mail']
                    customer.save()
                    return HttpResponse(json.dumps(ResponseData.get_message_eighteen(), ensure_ascii=False))
            elif get_page_info['customer_address'] != '':
                customer.customer_address = get_page_info['customer_address']
                customer.save()
                return HttpResponse(json.dumps(ResponseData.get_message_eighteen(), ensure_ascii=False))
        else:
            return HttpResponse(json.dumps(ResponseData.get_message_nineteen(), ensure_ascii=False))
    else:
        return HttpResponse(json.dumps(ResponseData.get_message_thirteen(), ensure_ascii=False))


# 查询用户的接口
def select_customer(request):
    get_page_info = get_customerinfo(request.POST)
    get_customer_name = CustomerInfo_2.objects.filter(customer_name=get_page_info['customer_name'])
    if get_page_info['customer_name'] is not None:
        if get_page_info['customer_name'] == '':
            return HttpResponse(json.dumps(ResponseData.get_message_three(), ensure_ascii=False))
        elif len(get_customer_name) >= 1:
            list1 = []
            for value in CustomerInfo_2.objects.filter(customer_name=get_page_info['customer_name']).values():
                list1.append(value)
            return HttpResponse(json.dumps(ResponseData.get_message_seventeen(list1), ensure_ascii=False))
        else:
            return HttpResponse(json.dumps(ResponseData.get_message_twentyone(), ensure_ascii=False))
    else:
        list2 = []
        for value in CustomerInfo_2.objects.all():
            dict1 = ({"id": value.id, "customer_name": value.customer_name, "customer_type": value.customer_type,
                      "customer_phone": value.customer_phone, "customer_mail": value.customer_mail,
                      "customer_address": value.customer_address})
            list2.append(dict1)
        total = CustomerInfo_2.objects.all().annotate(Count('id'))
        total = total[0].id__count
        print(total)
        return HttpResponse(json.dumps(ResponseData.get_message_seventeen(list2), ensure_ascii=False))


# 删除客户的接口
def delete_customer(request):
    get_page_info = get_customerinfo(request.POST)
    get_customer_name = CustomerInfo_2.objects.filter(customer_name=get_page_info['customer_name'])
    if get_page_info['customer_name'] is not None:
        if len(get_customer_name) == 1:
            customer = CustomerInfo_2.objects.get(customer_name=get_page_info['customer_name'])
            customer.delete()
            return HttpResponse(json.dumps(ResponseData.get_message_twenty(), ensure_ascii=False))
        else:
            return HttpResponse(json.dumps(ResponseData.get_message_nineteen(), ensure_ascii=False))
    else:
        return HttpResponse(json.dumps(ResponseData.get_message_thirteen(), ensure_ascii=False))

(4)修改AddCustomer_2/models.py

from django.db import models

# Create your models here.
from django.db import models


# 必须要继续models.Model,不然同步数据会出现问题
class CustomerInfo_2(models.Model):
    # 声明客户类型的选择:
    customer_choice = [("A", "A类客户"), ("B", "B类客户"), ("C", "C类客户")]
    # name是数据库表中的名称,一般就不需要指定咯,verbose_name是导出Excel或者csv文件时首行的字段说明
    # customer_name是类的属性
    # django会自动生成一个id,如果你不想要这个id,可以自定义一个
    # 实在不需要ID的话,则需要指定主键
    customer_name = models.CharField(max_length=12, verbose_name='客户名称', unique=True, primary_key=True)
    # customer_name = models.CharField(max_length=12, verbose_name='客户名称', unique=True, primary_key=True, null=True)
    customer_type = models.CharField(max_length=2, verbose_name='客户分类', choices=customer_choice, null=True)
    # IntegerField不需要指定长度
    customer_phone = models.BigIntegerField(verbose_name='手机号码', null=True)
    customer_mail = models.EmailField(max_length=20, verbose_name='电子邮箱', null=True)
    customer_address = models.CharField(max_length=100, verbose_name='详细地址')

(5)public下的代码

# -*-coding:utf-8-*-#
#一些逻辑判断的封装

from Public.Get_CustromerInfo import get_customerinfo

class Check_Data():
    def __init__(self, method_obj):
        self.get_page_info = get_customerinfo(method_obj)

    # 判断所有必传参数是是否有传
    def judge_allpars_notNone(self):
        if self.get_page_info["customer_name"] is not None and self.get_page_info["customer_type"] is not None and self.get_page_info["customer_phone"] is not None and \
                self.get_page_info["customer_mail"] is not None:
            return True
        else:
            return False

    # 判断所有必填参数的值是否为空
    def judge_allpars_Null(self):
        if self.get_page_info["customer_name"] == '' and self.get_page_info["customer_type"] == '' and \
                self.get_page_info["customer_phone"] == '' and self.get_page_info["customer_mail"] == '':
            return True
        else:
            return False

    def judge_comseter_type(self):
        if self.get_page_info["customer_type"] not in ["A", "B", "C"]:
            return True
        else:
            return False
# -*-coding:utf-8-*-#
# Get_CustromerInfo
# 从页面上获取接口的数据
def get_customerinfo(method_obj):
    get_page_info = {"customer_name": method_obj.get("customer_name"),
                     "customer_type": method_obj.get("customer_type"),
                     "customer_phone": method_obj.get("customer_phone"),
                     "customer_mail": method_obj.get("customer_mail"),
                     "customer_address": method_obj.get("customer_address")}
    return get_page_info
# -*-coding:utf-8-*-#
#JudgeMethod
# 判断的一些方法封装
# -----------------------------------------------
import re


class JudgeMethod():
    @staticmethod
    def judge_isdigit(value):
        if value.strip().isdigit():
            return True
        else:
            return False

    # 判断是否为133/187/188/189开头
    @staticmethod
    def judge_head(value):
        if re.match(r"^133", value) or re.match(r"^18[7,8,9]", value):
            return True
        else:
            return False

    # 判断是否为163.com或者qq.com结尾
    @staticmethod
    def judge_tail(value):
        if re.match(r"[0-9a-zA-Z_]{0,13}@163.com", value) or re.match(r"[0-9a-zA-Z_]{0,13}@qq.com", value):
            return True
        else:
            return False
# -*-coding:utf-8-*-#
# ResponseData
# 响应内容的封装
# -----------------------------------------------
class ResponseData():
    @staticmethod
    def get_message_one():
        return {"reason": "客户名称、客户分类、联系人、手机号码和电子邮箱不能为空", "result": [], "error_code": 2013}

    @staticmethod
    def get_message_two():
        return {"reason": "数据库中已存在同名的客户", "result": [], "error_code": 2000}

    @staticmethod
    def get_message_three():
        return {"reason": "请填写客户名称", "result": [], "error_code": 2001}

    @staticmethod
    def get_message_four():
        return {"reason": "客户名称的长度必须为6-12个字符", "result": [], "error_code": 2002}

    @staticmethod
    def get_message_five():
        return {"reason": "请填写客户分类", "result": [], "error_code": 2003}

    @staticmethod
    def get_message_six():
        return {"reason": "客户分类不存在", "result": [], "error_code": 2004}

    @staticmethod
    def get_message_seven():
        return {"reason": "请填写手机号码", "result": [], "error_code": 2007}

    @staticmethod
    def get_message_eight():
        return {"reason": "手机号码的长度必须为11位", "result": [], "error_code": 2008}

    @staticmethod
    def get_message_nine():
        return {"reason": "手机号码只能为数字", "result": [], "error_code": 2009}

    @staticmethod
    def get_message_ten():
        return {"reason": "手机号码只能以133/187/188/189开头", "result": [], "error_code": 2010}

    @staticmethod
    def get_message_eleven():
        return {"reason": "请填写电子邮箱", "result": [], "error_code": 2011}

    @staticmethod
    def get_message_twelve():
        return {"reason": "电子邮箱只能为QQ或者163邮箱", "result": [], "error_code": 2012}

    @staticmethod
    def get_message_thirteen():
        return {"reason": "缺少客户名称参数", "result": [], "error_code": 2014}

    @staticmethod
    def get_message_fourteen():
        return {"reason": "缺少客户分类参数", "result": [], "error_code": 2015}

    @staticmethod
    def get_message_fiveteen():
        return {"reason": "缺少手机号码参数", "result": [], "error_code": 2017}

    @staticmethod
    def get_message_sixteen():
        return {"reason": "缺少电子邮箱参数", "result": [], "error_code": 2018}

    @staticmethod
    def get_message_seventeen(values):
        return {"reason": "sucess", "result": values, "error_code": 0}

    @staticmethod
    def get_message_eighteen():
        return {"reason": "修改成功", "error_code": 000000}

    @staticmethod
    def get_message_nineteen():
        return {"reason": "客户名称不存在", "error_code": 100000}

    @staticmethod
    def get_message_twenty():
        return {"reason": "删除成功", "error_code": 0000}

    @staticmethod
    def get_message_twentyone():
        return {"reason": "数据库中不存在该数据", "error_code": 100001}

(6)启动Django即可

启动方式参考【10.4 Django项目实操1 】中的【 (5) 启动 Django 服务】

**10.8 Django项目实操

3-对客户信息增删改查的设计**项目实操2是传统的方式:先进行数据库连接,再判定数据缺点:过于麻烦解决方案:可采用模型层优化,需应用到ORM模式ORM模式参考:https://blog.csdn.net/qq_31851107/article/details/104646005

需求:Django对客户信息增删改查的设计新建app AddCustomer2

(1)修改settings.py文件,配置mysql数据库连接

默认sqlite,本次采用mysql

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',   #指定数据库的引擎
        'NAME': 'testdb',    #如果使用mysql、oracle等数据库的话,那么必须先自己创建一个数据库,指定一个数据库,django会在当前数据库中完成表的创建
        'USER': 'root',   #mysql的用户名 密码
        'PASSWORD': 'password',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }

}

(2)修改models.py文件,声明类,该类对应数据库的表结构

from django.db import models


# 创建一个用户信息表
# 如果你需要将当前类映射到指定数据库完成对应表结构的创建的话,那么当前类必须继承models.Modle,否则的无法生成迁移文,那么就无法实现数据同步操作
# 就相当于是一个普通类
class CustomerInfo(models.Model):
    # 声明客户类型的选择:
    customer_chocie = [("A", "A类客户"), ("B", "B类客户"), ("C", "C类客户")]
    # 例如:将数据导出到execl等文件中,首行都是每列的描述verbose_name;如果不想自动让django默认添加一个id的字段,那么可以自定义id,并将该id的值
    # 设置为主键,那么默认的就不存在,如果不想自定义id的话也不想要自动生成的那个id,那么在当前表中指定一个字段为主键
    # customer_name就是一个主键
    customer_name = models.CharField(max_length=12, name="cus_name", verbose_name="客户名称", primary_key=True)
    customer_type = models.CharField(max_length=2, choices=customer_chocie, name="cus_type")
    # 如果是使用integerField的话则不需要声明其长度
    customer_phone = models.IntegerField()
    customer_email = models.CharField(max_length=20)
    customer_address = models.CharField(max_length=100, null=True)

    # 客户名称格式:6 - 12  # 字符  # 客户分类固定:A、B、C  # 联系人:6 - 12  # 字符  # 手机号码:11  # 位:固定格式(133 / 187 / 188 / 189)  # 电子邮箱:163、qq  # 详细地址:

(3)修改settings.py文件,注册app名为AddCustomer

Python 全栈测试开发 Chapter10:接口的设计与开发_字段_46

(4)创建mysql数据库中的表

接下来要在pycharm的teminal中通过命令创建数据库的表了。有2条命令,分别是:

python manage.py makemigrations
python manage.py migrate

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_47

(1)修改views.py,对表进行插入、修改、删除、查询 操作

操作模型层有2种办法:

a.操作模型层办法1:

通过Django响应完成,如下所示add_customer,通过请求获取到相应的参数,将数据插入表中,完成客户新增操作

from django.shortcuts import render

# Create your views here.
# 完成新增客户信息# 客户名称格式:6 - 12
# 字符
# 客户分类固定:A、B、C
# 联系人:6 - 12
# 字符
# 手机号码:11
# 位:固定格式(133 / 187 / 188 / 189)
# 电子邮箱:163、qq
# 详细地址:
from django.http import HttpResponse
from AddCustomer.models import CustomerInfo


def add_customer(request):
    # 从页面上获取的数据,传入的参数
    get_info = {"cus_name": request.GET.get("customer_name"), 
                "cus_type": request.GET.get("customer_type"),
                "customer_phone": request.GET.get("customer_phone"),
                "customer_email": request.GET.get("customer_email"),
                "customer_address": request.GET.get("customer_address")}
    # 前面可以实现一个一个赋值操作
    customer = CustomerInfo.objects.create(**get_info)
    return HttpResponse("新增客户成功")


# 要将mysql中的数据库中的数据查询出来,显示json格式或者写入到静态页面
def select_data(request):
    # 获取到queryset对象
    # for value in CustomerInfo.objects.all():
    #     print(value.cus_name)  #其中value是表对象,cus_name是表的字段
    #     print(value.cus_type)
    # 查询出以l为开头的姓名的或者以qq.com为结尾的客户姓名
    # 查询第一条记录
    print("第一条记录", CustomerInfo.objects.values().first())
    # startswith、endwith、first、last
    for value in CustomerInfo.objects.filter(customer_email__endswith='@qq.com').values():  # 字段名__关键字
        print("以qq.com结尾的客户是:", value["cus_name"])

    return HttpResponse("查询成功")

b.操作模型层办法2:

通过python main()直接执行操作,前提配置DJANGO_SETTINGS_MODULE的环境变量配置DJANGO_SETTINGS_MODULE的环境变量方法有三种1)根据文件configurations设置添加-针对当前文件

Python 全栈测试开发 Chapter10:接口的设计与开发_sqlite_48

ps:需重启pycharm 2)代码形式添加-针对当前文件

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE","InterfaceProgram.settings")

3)DJANGO_SETTINGS_MODULE变量直接配置在计算机中