栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Django学习笔记3

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Django学习笔记3

三、模型层 3.1 预备知识

静态文件:图片,css,js,音频,视频

静态文件配置 - settings.py

1.配置静态文件的访问路径

通过那个url地址找静态文件

STATIC_URL = ‘/static/’

说明:

指定访问静态文件时是需要通过/static/xxx或http://127.0.0.1:8000/static/xxx[xxx表示具体的静态资源位置]

2.配置静态文件的存储路径STATICFILES_DIRS

STATICFILES_DIRS保存的是静态文件在服务器端的存储位置

# file: settings.py
STATICFILES_DIRS = (	
os.path.join(base_DIR, "static"),
)

模板中访问静态文件 - img标签为例

通过{% static %}标签访问静态文件

  1. 加载static - {% load static %}
  2. 使用静态资源 - {% static ‘静态资源路径’ %}
  3. 样例:

Django应用和分布式路由

应用在Django项目中是一个独立的业务模块,可以包含自己的路由,视图,模板,模型

创建应用

  1. 用manage.py中的子命令startapp创建应用文件夹

    python3 manage.py startapp music

  2. 在settings.py的INSTALLED_APPS列表中配置安装此应用

    setttings.py配置样例

    INSTALLED_APPS = [    # ....    
    	'user',	#用户信息模块    
    	'music', #音乐模块
    ]
    

分布式路由

Django中,主路由配置文件(urls.py)可以不处理用户具体路由,主路由配置文件的可以做请求的奋发(分布式请求处理)。具体的请求可以由各自的应用来进行处理。

步骤1 - 主路由中调用include函数

语法:include(‘app名字.url模块名’)

作用:用于将当前路由转到各个应用的路由配置文件的urlpatterns进行分布式处理

以http://127.0.0.1:8000/music/index为例:

from django.urls import path,include
from . import views
urlpatterns = [  
  path('admin/', admin.site.urls),    
  path('test_static', views.test_static),  
  path('music/', include('music.urls'))
]

练习 - 配置分布式路由

  1. 创建两个应用

    创建sport应用,并注册

    创建news应用,并注册

  2. 创建分布式路由系统

    http://127.0.0.1:8000/sport/index

    交给sport应用中的index_view()函数处理

    http://127.0.0.1:8000/news/index

    交给news应用中的index_view()函数处理

应用下的模板

应用内部可以配置模板目录

  1. 应用下手动创建templates文件夹

  2. settings.py开启应用模板功能

    TEMPLATE配置项中的’APP_DIRS’值为True即可

    应用下templates和外层templates都存在时,django得查找模板规则

    • 优先查找外层templates目录下的模板
    • 按INSTALLED_APPS配置下的应用顺序逐层查找
3.2 模型层引入

定义 - 负责和数据库之间进行通信

Django配置mysql

  • 安装mysqlclient

  • 安装前确认ubuntu是否已安装python3-dev和default-libmysqlclient-dev

    1.sudo apt list --installed|grep -E ‘libmysqlclient-dev|python3-dev’

    2.若命令无输出则需要安装 - sudo apt-get install python3-dev default-libmysqlclient-dev

  • sudo pip3 install mysqlclient

创建数据库

进入mysql数据库执行

  • create database 数据库名 default charset utf8
  • 通常数据库名跟项目名保持一致

settings.py里进行数据库的配置

  • 修改DATAbaseS配置项的内容,由sqlite3变为mysql

  • ENGINE - 指定数据库存储引擎

    'django.db.backends.mysql'
    'django.db.backends.sqlite3'
    'django.db.backends.oracle'
    'django.db.backends.postgresql'
    
  • NAME - 指定要连接的数据库的名称

  • USER - 指定登录到数据库的用户名

  • PASSWORD - 数据库的密码

  • HOST/PORT - 连接具体数据库的IP和端口

什么是模型

  • 模型是一个Python类,它是由django.db.models.Model派生出的子类

  • 一个模型类代表数据库中的一张数据表

  • 模型类中每一个类属性都代表数据库中的一个字段

  • 模型是数据交互的接口,是表示和操作数据库的方法和方式

3.3 ORM框架

定义:ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,它允许你使用类和对象对数据库进行操作,从而避免通过SQL语句操作数据库

作用:

  1. 建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库
  2. 根据设计的模型类生成数据库中的表格
  3. 通过简单的配置就可以进行数据库的切换

优点:

  1. 只需要面向对象编程,不需要面向数据库编写代码
  2. 实现了数据模型与数据库的解耦,屏蔽了不同数据库操作上的差异

缺点:

  1. 对于复杂业务,使用成本较高
  2. 根据对象的操作转换成SQL语句,根据查询的结果转化为对象,在映射过程中有性能损失

映射图

模型示例

此示例为添加一个bookstore_book数据表来存放图书馆中书目信息

  1. 添加一个bookstore的app

    python3 manage.py startapp bookstore

  2. 添加模型类并注册app

# file : bookstore/models.pyfrom django.db import modelsclass Book(models.Model):    
	title = models.CharField("书名", max_length=50, default='')    
	price = models.DecimalField("定价", max_digits=7, decimal_places=2, default=0.0)
  1. 数据库迁移

    迁移是Django同步您对模型所做更改(添加字段,删除模型等)到您的数据库模式的方式

    生成迁移文件 - 执行python3 manage.py makemigrations

    • 将应用下的models.py文件生成一个中间文件,并保存在migratinos文件夹中

    执行迁移脚本程序 - 执行python3 manage.py migrate

    • 执行迁移程序实现迁移。将每个应用下的migrations目录中的中间文件同步回数据库

模型类创建

from django.db import modelsclass 
模型类名(models.Model):    
	字段名 = models.字段类型(字段选项)
3.4 ORM基础字段和选项

创建模型类流程

  • 创建应用

  • 在应用下的models.py编写模型类

    from django.db import models
    class 模型类名(models.Model):    
    	字段名 = models.字段类型(字段选项)
    
  • 迁移同步 makemigrations&migrate

  • 任何关于表结构的修改,务必在对应模型类上修改

  • 例:为bookstore_book表添加一个名为info的字段varchar(100)

    解决方案 ->

    模型类中添加对应类属性

    执行数据库迁移

字段类型

  • BooleanField()

    数据库类型:tinyint(1)

    编程语言中:使用True或False来表示值

    在数据库中:使用1或0来表示具体的值

  • CharField()

    数据库类型:varchar

    注意:必须要指定max_length参数值

  • DateField()

    数据库类型:date

    作用:表示日期

    参数:

    auto_now:每次保存对象时,自动设置该字段为当前时间(取值:true/false)

    auto_now_add:当对象第一次被创建时自动设置当前时间(取值:true/false)

    default:设置当前时间(取值:字符串格式时间如:‘2019-6-1’)

    以上三个参数只能多选一

  • DateTimeField()

    数据库类型:datetime(6)

    作用:表示日期和时间

    参数同DateField

  • FloatField()

    数据库类型:double

    编程语言中和数据库中都使用小数表示值

  • DecimalField()

    数据库类型:decimal(x,y)

    编程语言中:使用小数表示该列的值

    在数据库中:使用小数

    参数:

    max_digits:位数总数,包括小数点后的位数。该值必须大于等于decimal_places

    decimal_places:小数点后的数字数量

  • EmailField()

    数据库类型:varchar

    编程语言和数据库中使用字符串

  • IntegerField()

    数据库类型:int

    编程语言和数据库中使用整数

  • ImageField()

    数据库类型:varchar(100)

    作用:在数据库中为了保存图片的路径

    编程语言和数据库中使用字符串

  • TextField()

    数据库类型:longtext

    作用:表示不定长的字符数据

  • 更多内容可见官方文档https://docs.djangoproject.com/en/2.2/ref/models/fields/#field-types

  • 练习:在bookstore/models.py应用中国添加一个模型类

    Author - 作者

    name - CharField 姓名 长度最大11

    age - IntegerField 年龄

    email - EmailField 邮箱

字段选项

  • 字段选项,指定创建的列的额外的信息

  • 允许出现多个字段选项,多个选项之间使用,隔开

  • primary_key

    如果设置为True,表示该列为主键,如果指定一个字段为主键,则此数据表不会创建id字段

  • blank

    设置为True时,字段可以为空。设置为False时,字段是必须填写的

  • null

    设置为True表示该列值允许为空

    默认为False,如果该选项为False建议加入default选项来设置默认值

  • default

    设置所在列的默认值,如果字段选项null=False建议添加此项

  • db_index

    如果设置为True,表示为该列增加索引

  • unique

    如果设置为True,表示该字段在数据库中的值必须是唯一(不能重复出现的)

  • db_column

    指定列的名称,如果不指定的话则采用属性名作为列名

  • verbose_name

    设置该字段在admin界面上的显示名称

  • 字段选项样例

    # 创建一个属性,表示用户名称,长度30个字符,必须是唯一的,不能为空,添加索引
    name = models.CharField(max_length=30, unique=True, null=False, db_index=True)
    
  • 更多内容可见官方文档https://docs.djangoproject.com/en/2.2/ref/models/fields/#field-options

    修改过字段选项最好执行makemigrations和migrate

meta类

使用内部meta类来给模型赋予属性,meta类下有很多内建的类属性,可对模型类做一些控制

示例:

# file: bookestore/models.py
from django.db import models
class Book(models.Model):    
	title = models.CharField("书名", max_length=50, default='')    
	price = models.DecimalField("定价", max_digits=7, decimal_places=2, default=0.0)
class meta:        
	db_table = 'book'	#可改变当前模型类对应的表名

练习

  1. 模型类 - Book 表名book

    title - CharField(50) - 书名

    pub - CharField(100) - 出版社

    price - DecimalField - 图书定价 总位7/小数点2位

    market_price - 图书零售价 总位7/小数点2位

  2. 模型类 - Author 表名author

    name - CharField(11) - 姓名 非空

    age - IntegerField - 年龄 默认值为1

    email - EmailField - 邮箱 允许为空

常见问题处理

问题1

错误原因

  • 当对模型类新添加一个字段时可出现错误
  • 原理是添加新字段后,数据库不知道原来已有数据对于新建字段该如何赋值,所以新增字段时,务必要添加default默认值

处理方法

  • 选择1 进入到shell中,手动输入一个默认值
  • 选择2 退出当前生成迁移文件的过程,自己取修改models.py,新增加一个default=XXX的缺省值(推荐使用)

问题2

  • 数据库迁移文件混乱的解决办法

  • 数据库中django_migrations表记录了migrate的’全过程’,项目各应用中的migrate文件应与之对应,否则migrate会报错

  • 解决方案:

    1. 删除所有migrations里所有的000?_XXXX.py(_init_.py除外)

    2. 删除数据库

      sql> drop database mywebdb;

    3. 重新创建数据库

      sql> create database mywebdb default charset…;

    4. 重新生成migrations里所有的000?_XXXX.py

      python3 manage.py makemigrations

    5. 重新更新数据库

      python3 manage.py migrate

3.5 ORM操作

基本操作包括增删改查操作,即CRUD

CRUD是指计算处理时的增加(Create)、读取查询(Read)、更新(Update)和删除(Delete)

核心 -> 模型类.管理器对象

每个继承自models.Model的模型类,都会有一个objects对象被同样继承下来。这个对象叫管理器对象。

数据库的增删改查可以通过模型的管理器实现

class MyModel(models.Model):    	
	...MyModel.objects.create(...) 
	#objects是管理器对象

创建数据

Django ORM使用一种直观的方式把数据库表中的数据表示成Python对象

创建数据中每一条记录就是创建一个数据对象

方案1

MyModel.objects.create(属性1=值1,属性2=值2)

成功:返回创建好的实体对象

失败:抛出异常

方案2

创建MyModel实例对象,并调用save()进行保存

obj = MyModel(属性=值,属性=值)

obj.属性=值

obj.save()

Django Shell

在Django提供了一个交互式的操作项目叫Django Shell,它能够在交互模式用项目工程的代码执行相应的操作

利用Django Shell可以代替编写view的代码来进行直接操作

注意:项目代码发生变化时,重新进入Django shell

启动方式:python3 manage.py shell

练习:利用Django shell给book添加如下数据

书名定价零售价出版社
Python20.0025.00清华大学出版社
Django70.0075.00清华大学出版社
JQuery90.0085.00机械工业出版社
Linux80.0065.00机械工业出版社
HTML590.00105.00清华大学出版社

查询操作

数据库的查询需要使用管理器对象进行

通过MyModel.objects管理器方法调用查询方法

方法说明
all()查询全部记录,返回QuerySet查询对象
get()查询符合条件的单一记录
filter()查询符合条件的多条记录
exclude()查询符合条件之外的全部记录
  • all()方法

    用法:MyModel.objects.all()

    作用:查询MyModel实体中所有的数据

    等同于select * from table

    返回值:QuerySet容器对象,内部存放MyModel实例

    from bookstore.models import Book
    books = Book.objects.all()
    for book in books:    
    	print("书名", book.title, '出版社', book.pub)
    

    查询方法

    可以在模型类定义_str_方法,自定义QuerySet中的输出格式

    例如,在Book模型类定义如下:

    def _str_(self):    
       return '%s_%s_%s_%s'%(self.title,self.price,self.pub,self.market_price)
    

    则在django shell中可得到如下输出

    >>> al = Book.objects.all()
    >>> al
    >>> , , , , ]>
    
  • values(‘列1’, ‘列2’…)

    用法:MyModel.objects.values(…)

    作用:查询部分列的数据并返回

    等同于select 列名1,列名2 from xxx

    返回值:QuerySet

    ​ 返回查询结果容器,容器内存字典,每个字典代表一条数据,格式为:{‘列1’:值1,‘列2’:值2}

  • values_list(‘列1’,‘列2’…)

    用法:MyModel.objects.values_list(…)

    作用:返回元组形式的查询结果

    等同于select 列1,列2 from xxx

    返回值:QuerySet容器对象,内部存放元组

    会将查询出来的数据封装到元组中,再封装到查询集合QuerySet中

  • order_by()

    用法:MyModel.objects.order_by(’-列’,‘列’)

    作用:与all()方法不同,它会用SQL语句的ORDER BY子句对查询结果进行根据某个字段选择性的进行排序

    说明:默认是安装升序排序,降序排序需要在列前增加’-'表示

练习

  • 制作’查看所有书籍’的页面

  • 视图函数all_book

  • url http://127.0.0.1:8000/bookstore/all_book

    idtitlepubpricemarket_priceop
    1python清华大学出版社2525更新 删除

条件查询

  • filter(条件)

    语法:MyModel.objects.filter(属性1=值1,属性2=值2)

    作用:返回包含此条件的全部数据集

    返回值:QuerySet容器对象,内部存放MyModel实例

    说明:当多个属性在一起时为"与"关系

    filter样例

    # 查询书中出版社为"清华大学出版社"的图书
    from bookstore.models import Book
    books = Book.objects.filter(pub="清华大学出版社")
    for book in books	
    	print("书名:", book.title)
    	# 查询Author实体中name为王老师并且age是28岁的
    	authors = Author.objects.filter(name='王老师',age=28)
    
  • exclude(条件)

    语法:MyModel.objects.exclude(条件)

    作用:返回不包含此条件的全部的数据集

    示例:查询清华大学出版社,定价等于50以外的全部图书

    books = models.Book.objects.exclude(pub="清华大学出版社",price=50)for book in books:    print(book)
    
  • get(条件)

    语法:MyModel.objects.get(条件)

    作用:返回满足条件的唯一一条数据

    说明:该方法只能返回一条数据,查询结果多余一条数据则抛出Model.MultipleObjectsReturned异常,查询结果如果没有数据则抛出Model.DoesNotExist异常

  • 如何做非等值查询?

  • 查询谓词

    定义:做更灵活的条件查询时需要使用查询谓词

    说明:每一个查询谓词是一个独立的查询功能

    _exact:等值匹配

    示例:

    Author.objects.filter(id__exact=1)
    # 等同于select * from author where id=1
    

    __contains:包含指定值

    示例:

    Author.objects.filter(name__contains='w')
    # 等同于select * from author where name like '%w%'
    

    __startswith:以XXX开始

    __endswith:以XXX结束

    __gt:大于指定值

    __gte:大于等于

    __lt:小于

    __lte:小于等于

    __in:查找数据是否在指定范围内

    示例:

    Author.objects.filter(country__in=['中国','日本','韩国'])
    # 等同于select * from author where country in ('中国','日本','韩国')
    

    __range:查找数据是否在指定的区间范围内

    示例:

    # 查找年龄在某一区间的所有作者		
    Author.objects.filter(age__range=(35,50))
    # 等同于select ... from author where age between 35 and 50
    

    更多内容可见官方文档https://docs.djangoproject.com/en/2.2/ref/models/querysets/#field-lookups

更新操作

修改单个实体的某些字段值的步骤

  1. 通过get()得到要修改的实体对象

  2. 通过对象.属性的方式修改数据

  3. 保存

    通过对象.save()保存数据

批量更新数据

直接调用QuerySet的update(属性=值)实现批量修改

示例:

# 将id大于3的所有图书价格定为0元
books = Book.objects.filter(id__gt=3)
books.update(price=0)
# 将所有书的零售价定为100元
books = Book.objects.all()
books.update(market_price=100)

删除操作

单个数据删除

步骤

  1. 查找查询结果对应的一个数据对象
  2. 调用这个数据对象的delete()方法实现删除
try:
    auth = Author.objects.get(id=1)
    auth.delete()
except:
    print(删除失败)

批量删除

步骤

  1. 查找查询结果集中满足条件的全部QuerySet查询集合对象

  2. 调用查询集合对象的delete方法实现删除

    # 删除全部作者中,年龄大于65的全部信息
    auths = Author.objects.filter(age__gt=65)
    auths.delete()
    

伪删除

  • 通常不会轻易在业务里把数据真正删掉,取而待之的是做伪删除,即在表中添加一个布尔型字段(is_active),默认是True;执行删除时,将欲删除数据的is_active字段置为False
  • 注意:用伪删除时,确保显示数据的地方,均加了is_active=True的过滤查询
3.6 F对象和Q对象

F对象

  • 一个F对象代表数据库中某条记录的字段的信息

  • 作用:

    通常是对数据库中的子段值在不获取的情况下进行操作

    用于类属性(字段)之间的比较

  • 语法:

    from django.db.models import F
    F('列名')
    

    示例1 更新Book实例中所有的零售价涨10元

    Book.objects.all().update(market_price=F('market_price')+10)
    # 以上做法好于如下代码
    books = Book.objects.all()
    for book in books:    
    	book.market_price=book.market_price+10    
    	book.save()
    

    示例2 对数据库两个字段的值进行比较,列出哪些书的零售价高于定价

    from django.db.models import F
    from bookstore.models import Book
    books = Book.objects.filter(market_price__gt=F('price'))
    for book in books:    
    	print(book.title, '定价:', book.price, '现价:', book.market_price)
    

Q对象

当在获取查询结果集使用复杂的逻辑或|、逻辑非~等操作时可以借助于Q对象进行操作

如:想找出定价低于20元或清华大学出版社的全部书,可以写成

Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社"))

Q对象在数据包django.db.models中。需要先导入再使用

示例:

from django.db.models import Q
# 查找清华大学出版社的书或价格低于50的书
Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清华大学出版社'))
# 查找不是机械工业出版社的书且价格低于50的书
Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社'))
3.7 聚合查询和原生数据库操作

聚合查询是指对一个数据表中的一个字段的数据进行部分或全部统计查询,查bookstore_book数据表中的全部书的平均价格,查询所有书的总个数等,都要使用聚合查询

聚合查询为

  • 整表聚合
  • 分组聚合

不带分组的聚合查询是指将全部数据进行集中统计查询

聚合函数[需要导入]:

  • 导入方法:from django.db.models import *
  • 聚合函数:Sum,Avg,Count,Max,Min

语法:MyModel.objects.aggregate(结果变量名=聚合函数(‘列’))

  • 返回结果:结果变量名和值组成的字典
  • 格式为{“结果变量名”:值}

分组聚合

分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成集合。

语法:

  • QuerySet.annotate(结果变量名=聚合函数(‘列’))

返回值:

  • QuerySet
  1. 通过先用查询结果MyModel.objects.values查找查询要分组聚合的列

    MyModel.objects.values(‘列1’,‘列2’)

    如:

    pub_set = Book.objects.values('pub')
    print(pub_set)
    
  2. 通过返回结果的QuerySet.annotate方法分组聚合得到分组结果

    QuerySet.annotate(名=聚合函数(‘列’))

    pub_count_set = pub_set.annotate(myCount=Count('pub'))
    print(pub_count_set) 
    #  

原生数据库操作

Django也可以支持用sql语句的方式通信数据库

查询:使用MyModel.objects.raw()进行数据库查询操作

语法:MyModel.objects.raw(sql语句,拼接参数)

返回值:RawQuerySet集合对象【只支持基础操作,比如循环】

books = models.Book.objects.raw('select * from bookstore_book')
for book in books:
    print(book)

使用原生语句时小心SQL注入

定义:用户通过数据上传,将恶意的sql语句提交给服务器,从而达到攻击效果

案例:用户在搜索好友的表单框里输入’1 or 1=1’

s1 = Book.objects.raw('select * from bookstore_book where id=%s'%('1 or 1=1'))

攻击结果:可查询出所有用户数据

完全跨过模型类操作数据库 - 查询/更新/删除

  1. 导入cursor所在的包

    from django.db import connection
    
  2. 用创建cursor类的构造函数创建cursor对象,再使用cursor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作

    from django.db import connection
    with connection.cursor() as cur:    
    	cur.execute('执行SQL语句', '拼接参数')
    

参考链接

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/326368.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号