Django测试开发学习笔记(一)

2020-08-12  本文已影响0人  DayBreakL

基础介绍

1. 简介

Django,发音为[dʒæŋɡəʊ],是用python语言写的开源web开发框架,并遵循MVC设计。Django的主要目:简便、快速的开发「数据库」驱动的网站。

学习网站:

官方网站: https://www.djangoproject.com/

github源码:https://github.com/django/django

django中文文档:https://yiyibooks.cn/xx/Django_1.11.6/index.html

2. 特点

![image](https://img.haomeiwen.com/i12041448/2817315ecaf2b5e8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

3. 环境搭建

4. 创建项目

![image](https://img.haomeiwen.com/i12041448/e15f6482897c18db?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

5. settings.py配置文件

6. Django常用命令

视图

1. 视图函数

2. 请求和响应

视图函数,围绕着两个对象进行:HttpResponse和HttpRequest

3. 类视图

>以函数的形式进行定义的视图就是函数视图,视图函数便于理解,但是遇到一个视图函数对应的路径提供了多种不同的HTTP请求方式的支持时(get,post,delete,put),需要在一个函数中写不同的业务逻辑,代码的可读性和复用性就很低, 所以,我们引入类视图进行解决。

路由

1. 单一路由

就是一个路径对应一个视图函数或者视图类

```
urlpatterns = [
    path('hello/',view.hello_world),
    path('',view.ViewDemo.as_view()),# 使用as_view()方法把类视图注册为视图
]
```

2. 基于正则的路由

前边的写法,我们在访问一个接口的时候,接口地址最后边必须要带一个/但是这样看着极度不美观。我们就可以通过基于正则表达式的路由帮我们解决。

注意:

3. 路由参数传递

4. 路由分发

路由分发指的是一个请求过来之后,怎么通过一级一级的转发,给到对应的程序处理;在django中一般指的是,从主app分发到子app中

image image

views.py

from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.

def hello_world(request):

    return HttpResponse('hello world')

urls.py

from django.urls import path, re_path

from . import views

urlpatterns = [
    re_path(r"^hello.?$",views.hello_world),
]
from django.urls import path, re_path, include

from django_project import view

urlpatterns = [
    path("v01/",include("app01.urls")) # 主路由中使用include转发至子路由中
]

5. url反向解析和命名空间(这个部分没懂,待补充,0524路由&视图)

在实际开发中,系统内部某些视图会通过redirect(url)重定向至其他的视图来处理,但是如果url地址被改掉了,我们通过url重定向就会失败,为了解决这个问题,引入了命名路由和命名空间的概念

ORM

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。 简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。 ORM在业务逻辑层和数据库层之间充当了桥梁的作用

让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。 几乎所有的软件开发过程中都会涉及到对象和关系数据库。在用户层面和业务逻辑层面,我们是面向对象的。 当对象的信息发生变化的时候,我们就需要把对象的信息保存在关系数据库中。 按照之前的方式来进行开发就会出现程序员会在自己的业务逻辑代码中夹杂很多SQL语句用来增加、读取、修改、删除相关数据, 而这些代码通常都是极其相似或者重复的

ORM解决的主要问题是对象和关系的映射。它通常将一个类和一张表一一对应,类的每个实例对应表中的一条记录, 类的每个属性对应表中的每个字段。 ORM提供了对数据库的映射,不用直接编写SQL代码,只需操作对象就能对数据库操作数据。 让软件开发人员专注于业务逻辑的处理,提高了开发效率。

ORM的缺点是会在一定程度上牺牲程序的执行效率。 ORM的操作是有限的,也就是ORM定义好的操作是可以完成的,一些复杂的查询操作是完成不了。 ORM用多了SQL语句就不会写了,关系数据库相关技能退化…

ORM只是一种工具,工具确实能解决一些重复,简单的劳动。这是不可否认的。 但我们不能指望某个工具能一劳永逸地解决所有问题,一些特殊问题还是需要特殊处理的。 但是在整个软件开发过程中需要特殊处理的情况应该都是很少的,否则所谓的工具也就失去了它存在的意义。

ORM 面向对象和关系型数据库的一种映射,通过操作对象的方式操作数据库数据,不支持对库的操作,只能操作表 对应关系: 类 --> 表 对象 --> 数据行 属性 --> 字段

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

每个模型都是一个Python类,它是django.db.models.Model的子类。模型的每个属性都代表一个数据库字段。
综上所述,Django为您提供了一个自动生成的数据库访问API,详询官方文档

1. 安装mysql

2. django连接配置数据库

3. ORM表模型

定义模型

在Django中,所有的模型必须继承from django.db.models import Model这个类,字段类型需要使用models模块中定义好的字段类型

from django.db import models

class Student(models.Model):  # 一个类对应一个表

# 类属性对应表中的字段,models.CharField这里对应字段的类型,这个是字符串类型
# max_length定义字段的最大长度
# 五大约束:非空约束(null=False,为默认,可不写)、主键约束(primary_key=True)、唯一约束(unique=True)、可空(null=True)、外键约束(通过models.ForeignKey()来指定)
# help_text添加该字段的备注信息,但没有加在数据库中,让自己看着比较清楚
# choices=((0, '男'), (1, '女')),表示该字段只有0,1两个值,0代表男,1代表女
#  models.DateTimeField 该字段是日期类型
# auto_now_add=True 在每一次数据被添加进去的时候,记录当前时间
# auto_now=True 在每一次数据被保存的时候,记录当前时间
    
    s_name = models.CharField(max_length=64,help_text="学生姓名")
    s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性别")
    s_phone = models.CharField(max_length=11, help_text="手机号")
    create_time = models.DateTimeField(auto_now_add=True)
    
    update_time = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'student'  # 指定表名,如果不指定表名,会用app名+类名生成表名


下图是mysql数据库字段和Models中定义类型的关系


image
模型中常用属性
image
django提供的一些特殊属性
EmailField(CharField):
    - 字符串类型,Django Admin以及ModelForm中提供验证机制
    - e_mail = models.EmailField(max_length=255, unique=True)

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   上传图片的宽度保存的数据库字段名(字符串)
自定义字段(了解即可)

示例:我们发现上边没有固定长度的字符串类型,但是手机号字段一般都是定长11位的字符串,所以我们需要自定义一些字段类型



from django.db import models

# Create your models here.

class PhoneField(models.Field):  # 自定义的char类型的字段类

    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super(PhoneField, self).__init__(max_length=max_length, *args, **kwargs)

    def db_type(self, connection):  # 限定生成数据库表的字段类型为char,长度为max_length指定的值的字符串
        return 'char(%s)' % self.max_length
Field的常用参数
image
模型中Meta配置:

对于一些模型级别的配置。我们可以在模型中定义一个类,叫做Meta。然后在这个类中添加一些类属性来控制模型的作用。

比如我们想要在数据库映射的时候使用自己指定的表名,而不是使用模型的名称。那么我们可以在Meta类中添加一个db_table的属性。示例代码如下:

class Book(models.Model):
    name = models.CharField(max_length=20,null=False)
    desc = models.CharField(max_length=100,name='description',db_column="description1")

    class Meta:
        db_table = 'book_model'
image
外键和表关系

4. ORM模型迁移

生成迁移脚本
![image](https://img.haomeiwen.com/i12041448/8322b9155e8bc7fa?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
执行迁移标本,数据库中创建新表
image

因为之前还做了别的操作,只想执行model_demo下的迁移脚本,所以可以在命令后面加上app的名字。

在数据库中创建了student表,django_migrations表存储了的是django的迁移记录。

image image

可以看看这些字段的约束和我们定义的一样:

image
迁移命令详解

5. abstract创建模型父类

在创建模型的时候,其实有好多字段都是模型中共同存在的,例如createtime,updatetime,mark等等,这些字段我们需要在每个模型中重复创建,这就造成了工作量的浪费,我们可以通过创建一个公共的模型父类来,子类集成该父类,这样我们就不需要重复写这些字段了

class PublicModel(models.Model):
    createtime = models.DateTimeField(auto_now_add=True,verbose_name="创建日期")
    updatetime = models.DateTimeField(auto_now=True,verbose_name = '修改日期')
    status = models.IntegerField(verbose_name = '状态')
    class Meta:
        abstract=True  # 父类中必须指定该属性,否则该类会被创建到数据库


# 子类继承PublicModel类,就不需要重复写createtime,update,status三个字段的定义了
class Student(PublicModel):
    s_name = models.CharField(max_length=64,help_text="学生姓名")
    s_sex = models.IntegerField(choices=((0, '男'), (1, '女')), help_text="性别")
    s_phone = models.CharField(max_length=11, help_text="手机号")

    class Meta:
        db_table = 'student'

6. ORM操作

ORM操作准备
新增数据
![image](https://img.haomeiwen.com/i12041448/51f8e1f7d480c0a8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

数据库新增了一条记录:

![image](https://img.haomeiwen.com/i12041448/294c9a2b6642c6f2?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
查找数据

查找数据都是通过模型下的objects对象来实现的

数据过滤
![image](https://img.haomeiwen.com/i12041448/6a67a6b89e507f30?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

`values()`展示详细的数据,更易读
`first()` 展示第一条数据
![image](https://img.haomeiwen.com/i12041448/92b1ad44c8ac97fe?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

常用的符号

![image](https://img.haomeiwen.com/i12041448/b2798ac9c8f03abb?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
其他查询方式
![image](https://img.haomeiwen.com/i12041448/a93aa961db53fe28?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
多条件查询
- 或 `|`
    ```
    # 筛选s_name='鲁班七号'或者s_sex=1
    stu=Student.objects.filter(Q(s_name='鲁班七号')|Q(s_sex=1))
    ```

    ![image](https://img.haomeiwen.com/i12041448/05954b20d16bdd4c?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

- 非 `~`
    ```
    stu=Student.objects.filter(~Q(s_sex=0))
    ```


    ![image](https://img.haomeiwen.com/i12041448/502a2ec8d476aa90?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
数据聚合-aggregate

sql中聚合函数有:max()、min()、count()、avg()、sum(),在ORM中如何表示?

使用聚合函数对数据进行统计操作,就需要使用到aggregate方法,返回的是一个字典。

aggregate是从整个查询结果集生成统计数据。

排序

排序使用order_by()

image
# 按id字段正序排列,默认为正序,由小到大
stu=Student.objects.filter(Q(s_name='鲁班七号')|Q(s_sex=0)).order_by("id")
# 按id字段倒序排列,加个符号
stu=Student.objects.filter(Q(s_name='鲁班七号')|Q(s_sex=0)).order_by("-id")
数据去重

去重使用.valuse("去重字段").distinct

# s_sex字段去重
stu=Student.objects.filter(s_sex=0).values("s_sex").distinct()
image
分页

使用django自带的分页器Paginator来对数据进行分页操作

分组
![image](https://img.haomeiwen.com/i12041448/a9aed20f130328f8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

所以,它还可以这样写,使用`count=Count('id')`
```
Student.objects.all().values('s_sex').annotate(count=Count('id')).values('s_sex','count')
```
![image](https://img.haomeiwen.com/i12041448/5221b6a94c135025?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
修改数据

get和filter查询出来的数据结构不一样,get查询出来的结果是一个对象,filter、exclude等查询出来的结果是一个查询集,他们的修改操作是不一样的。

删除数据

在查找到数据后,便可以进行删除了。删除数据非常简单,只需要调用这个对象的delete方法即可。

stu = Student.objects.get(id='6')
stu.delete()
事务和回滚

7. ORM多表关联

image
关联关系
关联模型创建
![image](https://img.haomeiwen.com/i12041448/9c7c7f28130527bb?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
代码示例

models.py

from django.db import models


# Create your models here.

# 学生表
class Stu(models.Model):
    s_name = models.CharField('学生姓名', max_length=64, null=False, help_text='学生姓名')
    s_sex = models.IntegerField('性别', max_length=1, choices=((0, '男'), (1, '女')), help_text='性别')
    s_age = models.PositiveIntegerField('年龄', null=False, default=0, help_text='年龄')
    s_dept = models.CharField("专业", max_length=64, null=False, help_text="专业")
    # 一对一关系,用models.OneToOneField(),关联放在使用频率较高的表中
    """
        models.OneToOneField()有三个参数:
            to:设置要关联的表名(类),
            to_field:设置要关联的表字段(类属性),
            on_delete:当关联字段删除时,s_id的值设置成什么,常用设置为models.CASCADE,表示当关联字段删除时,它也删除
    """
    """
        related_name:一般可以使用当前表_关联表来命名
            正向查询时,通过s_id可以查询student_info表中的数据,
            反向查询(从student_info表查询student表数据时)使用related_name进行查询
    """
    # db_column指定表字段列名
    si_id = models.OneToOneField(to='StudentInfo', to_field="id", on_delete=models.CASCADE, db_column='si_id',
                                 related_name="stu_stu_info")
    
    # 多对多关系会自动生成一张中间表,db_table是对中间表的命名
    course = models.ManyToManyField(to="Course", db_table="stu_course", related_name="course_student")

    class Meta:
        db_table = 'stu'

# 学生信息表
class StudentInfo(models.Model):
    s_card = models.CharField("身份证号", max_length=18, null=False, unique=True)
    s_phone = models.CharField(max_length=11, null=False, unique=True, help_text="手机号")
    s_addr = models.CharField("家庭住址", max_length=128, help_text="家庭住址")

    class Meta:
        db_table = "student_info"

# 课程表
class Course(models.Model):
    c_name = models.CharField('课程名',max_length=64,null=False,help_text="课程名")
    t_id = models.ForeignKey(to="Teacher",to_field="id",on_delete=models.CASCADE,related_name='teacher_course',db_column='t_id',help_text="老师编号")

    class Meta:
        db_table="course"

# 成绩表
class Score(models.Model):
    s_id = models.ForeignKey(to="Stu", to_field="id", on_delete=models.CASCADE, related_name='stu_score',
                             db_column='s_id', help_text="学生编号")
    c_id = models.ForeignKey(to="Course", to_field="id", on_delete=models.CASCADE, related_name='course_score',
                             db_column='c_id', help_text="学生编号")
    score = models.PositiveIntegerField("成绩",null=False,default=0,help_text="成绩")

    class Meta:
        db_table = "score"

# 老师表
class Teacher(models.Model):
    t_name = models.CharField("老师姓名", max_length=64,null=False,help_text="老师姓名")

    class Meta:
        db_table = "teacher"

数据迁移:

python manage.py makemigrations
python manage.py migrate multi_table
关联模型操作

增删改,都是单表操作,只有查询涉及多表,我们就主要讲下查询的多表操作

![image](https://img.haomeiwen.com/i12041448/80e0c140a41b85fe?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

8. QuerySet常用API

我们通常做查询操作的时候,都是通过模型名字.objects的方式进行操作。其实模型名字.objects是一个django.db.models.manager.Manager对象,而Manager这个类是一个“空壳”的类,他本身是没有任何的属性和方法的。他的方法全部都是通过Python动态添加的方式,从QuerySet类中拷贝过来的。

所以我们如果想要学习ORM模型的查找操作,必须首先要学会QuerySet上的一些API的使用。

返回新的QuerySet的方法
什么时候Django会将QuerySet转换为SQL去执行

9. 多数据库配置

(暂用不到,知道可以配置多数据库,要用的时候再学吧)

10. 执行sql语句

Manager.raw(raw_query, params=None, translations=None)

image

带参数的SQL

image
上一篇 下一篇

猜你喜欢

热点阅读