在MySQL中,表有两种引擎,一种是InnoDB,另外一种是myisam。如果使用的是InnoDB引擎,是支持外键约束的。外键的存在使得ORM框架在处理表关系的时候异常的强大。因此这里我们首先来介绍下外键在Django中使用。
class ForeignKey(ForeignObject): def __init__(self, to, on_delete):类定义为class ForeignKey(to,on_delete)。第一个参数是引用的是哪个模型,第二个参数是在使用外键引用的模型数据被删除了,这个字段该如何处理,比如有CASCADE 、 SET_NULL。
注意
一个Category模型可以有对应多个模型,为什么?因为Category对应过来是分类。
一个Article只能有一个Category,并且通过外键进行引用。
使用ForeignKey来定义模型之间的关系。
ForeignKey是由引用的模型来影响当前模型。
from django.db import models # category : 分类的意思 # 该类为分类 class Category(models.Model): name = models.CharField(max_length=100) # 该类为文章类 class Article(models.Model): title = models.CharField(max_length=100) content = models.TextField() # Foreign key 对应的是映射主键 # ForeignKey对应着第一个参数为要引用的模型,第二个参数为使用外键引用的模型被删除之后的字段处理 # CASCADE 为级联删除 category = models.ForeignKey('Category', on_delete=models.CASCADE)from django.shortcuts import render from .models import Article, Category from django.http import HttpResponse def index(request): category = Category(name='Python') # 先要保存好引用模型的实例 category.save() article = Article(title='Python数据分析', content='主要学习的内容有Numpy、Pandas、Matplotlib、Seaborn') # 这一步就完成了外键与表之间的映射 # 让对应Article中的category这个外键关系等于对应实例化模型 article.category = category article.save() return HttpResponse('首页')
想要引用另外一个app的模型,那么应该是传递to参数的时候,使用app.model_name进行指定。
使用另外APP下的外键:对应的APP.对应的模型
user/models.py
class UserName(models.Model): username = models.CharField(max_length=100)front/models.py
# 对应的文章 class Article(models.Model): title = models.CharField(max_length=20) # TextField 可以不需要指定长度 content = models.TextField() # ForeignKey默认传递两个参数。 # to-->对应的模型的名字 # on_delete --> 对应模型的外键删除操作 # 使用对应的外键 ForeignKey category = models.ForeignKey('Category', on_delete=models.CASCADE) # 当想使用user下的models作为外键时 author = models.ForeignKey('user.UserName', on_delete=models.CASCADE, null=True)front/views.py
from django.shortcuts import render from django.http import HttpResponse from .models import Article, Category from user.models import UserName def index(request): article = Article(title='Python3反爬虫原理与绕过实战', content='解决反爬虫原理') article.category = Category(pk=1) article.author = UserName(pk=1) article.save() return HttpResponse('这是首页')如果模型的外键引用的是本省自己这个模型,那么to参数可以为self,或者是这个模型的名字。在论坛开发中,一般评论都可以进行二级评论,即可以针对另外一个评论进行评论,那么在定义模型的时候就需要使用外键来引用自身。
# 该模型为引用自身模型来进行设置主键 # Comment : 评论 class Comment(models.Model): content = models.TextField() origin_comment = models.ForeignKey('self', on_delete=models.CASCADE, null=True)CASCADE : 级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除
# CASCADE : 当外键被删除,字段也会跟着删除 category = models.ForeignKey('Category', on_delete=models.CASCADE)PROTECT : 受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。
# PROTECT : 当有字段引用外键时,该外键是是不能删除的,受保护的情况 category = models.ForeignKey('Category', on_delete=models.PROTECTSET_NULL : 设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
# SET_NULL : 前提的情况是该外键字段可以设置为空的时候,才能进行操作 category = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True)SET_DEFAULT : 设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置默认值。如果设置这个选项,前提是要指定这个字段一个默认值。
# SET_DEFAULT : 前提的情况是该外键字段可以设置默认值,才能进行操作 category = models.ForeignKey('Category', on_delete=models.SET_DEFAULT, default=2)SET() : 如果外键的那条数据被删除了。那么将会获得SET函数中的值来作为这个外键的值。SET函数可以接受一个可以调用的对象(比如函数或者方法),如果是可以调用对象,那么会将这个对象调用后的结果作为值返回
DO_NOTHING: 不采取任何行为。一切全看数据库级别的约束。
查询是数据库操作中一个非常重要的技术。查询一般就是使用filter、exclude、get三个方法来实现。我们可以在调用这些方法的时候传递不同的参数来实现查询需求。在ORM层面,这些查询条件都是使用field+__+condition的方式来使用的。
数据源
get
使用get来查询数据的话,查询数据不存在的情况下,会报错。返回的类型为<class 'front.models.Article'> article = Article.objects.get(pk__exact=1) 打印原生的SQL语句,通过from django.db import connectionconnection.queriesfilter
使用filter来查询数据的话,当数据不存在返回<QuerySet []>返回的类型为<class 'django.db.models.query.QuerySet'> article = Article.objects.filter(pk__exact=1) 打印原生的SQL语句,通过article.query来实现使用精确的=进行查找,如果提供的是一个None,那么在SQL层面就是被解释为NULL
article = Article.objects.get(pk__exact=1) print(article) print(connection.queries) #----------# # 结果 Article{title:Python3网络爬虫, author:small-j, category:1} [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT `front_article`.`id`, `front_article`.`title`, `front_article`.`author`, `front_article`.`category_id` FROM `front_article` WHERE `front_article`.`id` = 1', 'time': '0.000'}, {'sql': 'SELECT `front_category`.`id`, `front_category`.`name` FROM `front_category` WHERE `front_category`.`id` = 1', 'time': '0.001'}] article = Article.objects.filter(pk__exact=None) print(article) print(article.query) #----------# # 结果 <QuerySet []> SELECT `front_article`.`id`, `front_article`.`title`, `front_article`.`author`, `front_article`.`category_id` FROM `front_article` WHERE `front_article`.`id` IS NULL使用like进行查询
article = Article.objects.filter(pk__iexact=1) print(article) print(article.query) #----------# # 结果 <QuerySet [<Article: Article{title:Python3网络爬虫, author:small-j, category:1}>]> SELECT `front_article`.`id`, `front_article`.`title`, `front_article`.`author`, `front_article`.`category_id` FROM `front_article` WHERE `front_article`.`id` LIKE 1大小写敏感
article = Article.objects.filter(title__contains='Python') print(article) print(article.query) # ------- # # 结果 <QuerySet [<Article: Article{title:Python3网络爬虫, author:small-j, category:1}>, <Article: Article{title:Python 数据分析, author:small-j, category:1}>]> SELECT `front_article`.`id`, `front_article`.`title`, `front_article`.`author`, `front_article`.`category_id` FROM `front_article` WHERE `front_article`.`title` LIKE BINARY %Python%大小写不敏感
article = Article.objects.filter(title__icontains='Python') print(article) print(article.query) # -------- # # 结果 <QuerySet [<Article: Article{title:Python3网络爬虫, author:small-j, category:1}>, <Article: Article{title:Python 数据分析, author:small-j, category:1}>, <Article: Article{title:python Django, author:small-j, category:1}>]> SELECT `front_article`.`id`, `front_article`.`title`, `front_article`.`author`, `front_article`.`category_id` FROM `front_article` WHERE `front_article`.`title` LIKE %Python%提取那些给定的field的值是否在给定的容器中。容器可以为list、tuple或者任何一个可以迭代的对象,包括QuerySet对象。
article = Article.objects.filter(pk__in=[1, 2, 3]) print(article) print(article.query) # --------- <QuerySet [<Article: Article{title:Python3网络爬虫, author:small-j, category:1}>, <Article: Article{title:Java开发实战, author:small-j, category:2}>, <Article: Article{title:mysql数据库认知, author:small-j, category:3}>]> SELECT `front_article`.`id`, `front_article`.`title`, `front_article`.`author`, `front_article`.`category_id` FROM `front_article` WHERE `front_article`.`id` IN (1, 2, 3) # 查询文章为id[1,2]的对应的文章分类 # 反向引用 # article__id__in category = Category.objects.filter(article__id__in=[1, 2]) print(category) print(category.query) return HttpResponse('删除成功') #-------# # 运行结果 <QuerySet [<Category: Category{name:Python}>, <Category: Category{name:java}>]> SELECT `front_category`.`id`, `front_category`.`name` FROM `front_category` INNER JOIN `front_article` ON (`front_category`.`id` = `front_article`.`category_id`) WHERE `front_article`.`id` IN (1, 2)某个field的值要大于给定的值
book = Book.objects.filter(price__gt=89) print(book) print(book.query) #---------- <QuerySet [<Book: {title:代码大全(第2版), america_author:[美] 史蒂夫·迈克康奈尔 , author: 金戈、汤凌、陈硕、张菲 译、裘宗燕 审校 , press: 电子工业出版社 , press_time: 2006-3 , price:128.0}>]> # 原生SQL语句 SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`press_time`, `book`.`price` FROM `book` WHERE `book`.`price` > 89.0某个field的值要大于等于给定的值
book = Book.objects.filter(price__gte=89) print(book) print(book.query) # -------- <QuerySet [<Book: {title:程序员修炼之道(第2版), america_author:David Thomas、Andrew Hunt , author: 云风 , press: 电子工业出版社 , press_time: 2020-4-1 , price:89.0}>, <Book: {title:代码大全(第2版), america_author:[美] 史蒂夫·迈克康奈尔 , author: 金戈、汤凌、陈硕、张菲 译、裘宗燕 审校 , press: 电子工业出版社 , press_time: 2006-3 , price:128.0}>]> # 原生SQL语句 SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`press_time`, `book`.`price` FROM `book` WHERE `book`.`price` >= 89.0某个field的值要小于给定的值
book = Book.objects.filter(price__lt=49) #----- <QuerySet [<Book: {title:计算机程序的构造和解释(原书第2版), america_author:Harold Abelson、Gerald Jay Sussman、Julie Sussman , author: 裘宗燕 , press: 机械工业出版社 , press_time: 2004-2 , price:45.0}>]> # 原生SQL语句 SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`press_time`, `book`.`price` FROM `book` WHERE `book`.`price` < 49.0某个field的值要小于等于给定的值
book = Book.objects.filter(price__lte=49) # ----- <QuerySet [<Book: {title:黑客与画家, america_author:[美] Paul Graham , author: 阮一峰 , press: 人民邮电出版社 , press_time: 2011-4 , price:49.0}>, <Book: {title:计算机程序的构造和解释(原书第2版), america_author:Harold Abelson、Gerald Jay Sussman、Julie Sussman , author: 裘宗燕 , press: 机械工业出版社 , press_time: 2004-2 , price:45.0}>]> # 原生SQL语句 SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`press_time`, `book`.`price` FROM `book` WHERE `book`.`price` <= 49.0判断某个字段在不在区域间
start_time = date(year=2020, month=7, day=3) end_time = date(year=2020, month=7, day=4) book = Book.objects.filter(now_time__range=(start_time, end_time)) print(book) print(book.query) # ------ <QuerySet [<Book: {title:黑客与画家, america_author:[美] Paul Graham , author: 阮一峰 , press: 人民邮电出版社 , press_time: 2011-4 , price:49.0, now_time:2020-07-04}>, <Book: {title:程序员修炼之道(第2版), america_author:David Thomas、Andrew Hunt , author: 云风 , press: 电子工业出版社 , press_time: 2020-4-1 , price:89.0, now_time:2020-07-03}>, <Book: {title:计算机程序的构造和解释(原书第2版), america_author:Harold Abelson、Gerald Jay Sussman、Julie Sussman , author: 裘宗燕 , press: 机械工业出版社 , press_time: 2004-2 , price:45.0, now_time:2020-07-03}>]> # 原生SQL语句 SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`press_time`, `book`.`price`, `book`.`now_time` FROM `book` WHERE `book`.`now_time` BETWEEN 2020-07-03 AND 2020-07-04针对某些date或者datetime类型的字段。可以指定date的范围。并且这个时间过滤,还可以以使用链式调用
book = Book.objects.filter(create_time__date=datetime(year=2020, month=7, day=5)) #------- <QuerySet [<Book: {title:Python深度学习, america_author:[美] 弗朗索瓦•肖莱 , author:张亮 , press: 人民邮电出版社 , price:119.0, create_time:2020-07-05 13:44:38}>]> # 原生SQL语句 SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`price`, `book`.`create_time` FROM `book` WHERE DATE(`book`.`create_time`) = 2020-07-05根据年份进行查找
book = Book.objects.filter(create_time__year=2020) # ------- <QuerySet [<Book: {title:利用Python进行数据分析, america_author:Wes McKinney , author: 唐学韬 , press: 机械工业出版社 , price:89.0, create_time:2020-07-03 13:46:21}>]> # SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`price`, `book`.`create_time` FROM `book` WHERE `book`.`create_time` BETWEEN 2020-01-01 00:00:00 AND 2020-12-31 23:59:59.999999 # 链式调用 book = Book.objects.filter(create_time__year__gt=2019) # --------- <QuerySet [<Book: {title:利用Python进行数据分析, america_author:Wes McKinney , author: 唐学韬 , press: 机械工业出版社 , price:89.0, create_time:2020-07-03 13:46:21}>]> # 原生SQL SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`price`, `book`.`create_time` FROM `book` WHERE `book`.`create_time` > 2019-12-31 23:59:59.999999根据时间进行查找
start_time = time(hour=13, minute=44) end_time = time(hour=13, minute=50) book = Book.objects.filter(create_time__time__range=(start_time, end_time)) #--------- <QuerySet [<Book: {title:Python深度学习, america_author:[美] 弗朗索瓦•肖莱 , author:张亮 , press: 人民邮电出版社 , price:119.0, create_time:2019-06-05 13:44:38}>, <Book: {title:深入理解计算机系统(原书第3版), america_author: Randal E.Bryant、David O'Hallaron , author:龚奕利、贺莲 , press: 机械工业出版社 , price:139.0, create_time:2019-06-04 13:49:41}>]> # 原生SQL SELECT `book`.`id`, `book`.`title`, `book`.`america_author`, `book`.`author`, `book`.`press`, `book`.`price`, `book`.`create_time` FROM `book` WHERE TIME(`book`.`create_time`) BETWEEN 13:44:00 AND 13:50:00求平均值。
from django.shortcuts import render from django.http import HttpResponse from .models import Book from django.db import connection # 导入聚合函数 from django.db.models import Avg def index(request): # 求书的价格的所以平均值 result = Book.objects.aggregate(Avg('price')) print(result) print(connection.queries) return HttpResponse('前端页面') # ---------------------- # 'proce__avg':这名字的由来,对应的APP的名字加上__avg {'price__avg': 97.25} # 原生SQL [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT AVG(`book`.`price`) AS `price__avg` FROM `book`', 'time': '0.001'}]当想指定其他名字的时候,可以这么做
result = Book.objects.aggregate(pirce=Avg('price'))聚合函数也支持查询条件的链式调用
# 求id价格大于2的平均值 result = Book.objects.filter(id__gt=2).aggregate(price=Avg('price')) print(result) print(connection.queries) #----------- {'price': 97.0} # SQL [{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT AVG(`book`.`price`) AS `price` FROM `book` WHERE `book`.`id` > 2', 'time': '0.001'}]获取指定的对象的个数
def count_views(request): # Count:为数据的个数 result = Book.objects.aggregate(count=Count('id')) print(result) print(connection.queries) return HttpResponse('聚合函数')获取指定对象的最大值和最小值
result = Author.objects.aggregate(min=Min('age')) result = Author.objects.aggregate(max=Max('age'))F表达式是用来优化ORM操作数据库的。
def F_data(request): # 给所有的图书升价 # F表达式使用的是update result = Book.objects.update(price=F('price')+10) print(result) return HttpResponse('F表达式')Q表达式是如果想要实现所有价格高于100元,并且评分达到4.8以上评分的图书
books = Book.objects.filter(price__gt=100, rating__gt=4.8)以上这个案例是一个并集查询,可以简单的通过传递多个条件进去来实现。但是如果想要实现一些复杂的查询语句,比如要查询所有价格高于100元,或者是评分低于4.8分的图书。那就没有办法通过传递多个条件进去实现了。这时候就需要使用Q表达式来实现了。
def Q_data(request): # 价格高于100元 或者评分达到4.8以上的评分 books = Book.objects.filter(Q(price__gt=100) | Q(rating__gt=4.8)) for book in books: print(book.name, book.price, book.rating) return HttpResponse('Q表示式')以上是进行或运算,当然还可以进行其他的运算,比如有&和~(非)等。
# 获取价格大于100,并且书名中包含"传"的图书 books = Book.objects.filter(Q(price__gte=100)&Q(name__contains="传")) # 获取书名包含"传",但是id不等于3的图书 books = Book.objects.filter(Q(name__contains='传') & ~Q(id=3))