1、外键和表关系
如果想要引用另外一个app的模型,那么应该在传递to参数的时候,使用app.model_name进行指定。如果User和Article不是在同一个app中。
models.py文件
from django.db import models
# 分类
class Category(models.Model):
name = models.CharField(max_length=100)
# 文章
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# author = models.ForeignKey("User",on_delete=models.CASCADE) 第一个参数指向关联的模型
category = models.ForeignKey("Category", on_delete=models.CASCADE)
# "user.User"中的user是app名称,该User模型是user这个app模型下面的,引入其他模型
author = models.ForeignKey("user.User", on_delete=models.CASCADE, null=True)
如果模型的外键引用的是本身自己这个模型,那么to参数可以为’self’,或者是这个模型的名字。在论坛开发中,一般评论都可以进行二级评论,即可以针对另外一个评论进行评论,那么在定义模型的时候就需要使用外键来引用自身。
class Comment(models.Model):
content = models.TextField()
origin_comment = models.ForeignKey('self',on_delete=models.CASCADE,null=True)
# 或者
# origin_comment = models.ForeignKey('Comment',on_delete=models.CASCADE,null=True)
2、外键删除操作
如果一个模型使用了外键。那么在对方那个模型被删掉后,该进行什么样的操作。可以通过on_delete来指定。可以指定的类型如下:
- 1.CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
from django.shortcuts import render
from .models import Article, Category
from django.http import HttpResponse
def delete_view(request):
category = Category.objects.get(pk=1)
# 分类表中的category是外键,删除该外键会影响到文章表中关联这个外键的文章表数据,级联删除
category.delete()
return HttpResponse("删除成功")
- 2.PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。
from django.db import models
# 分类
class Category(models.Model):
name = models.CharField(max_length=100)
# 文章
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# PROTECT,不允许删除引用了外键的数据
category = models.ForeignKey("Category", on_delete=models.PROTECT)
- 3.SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
from django.db import models
# 分类
class Category(models.Model):
name = models.CharField(max_length=100)
# 文章
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# SET_NULL 设置为空 前提必须允许为空
category = models.ForeignKey("Category", on_delete=models.SET_NULL, null=True)
- 4.SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。
from django.db import models
# 分类
class Category(models.Model):
name = models.CharField(max_length=100)
# 文章
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# SET_DEFAULT 设置为默认值,前提需要先给默认值
category = models.ForeignKey("Category", on_delete=models.SET_DEFAULT, default=Category.objects.get(pk=2))
- 5.SET():如果外键的那条数据被删除了。那么将会获取SET函数中的值来作为这个外键的值。SET函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。
from django.db import models
# 分类
class Category(models.Model):
name = models.CharField(max_length=100)
# 文章
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# 设置值
category = models.ForeignKey("Category", on_delete=models.SET(Category.objects.get(pk=4)))
- 6.DO_NOTHING:不采取任何行为。一切全看数据库级别的约束。
# 不采取任何行为。一切全看数据库级别的约束
category = models.ForeignKey("Category", on_delete=models.DO_NOTHING)
以上这些选项只是Django级别的,数据级别依旧是RESTRICT!
数据库层面的约束有四种:
- RESTRICT:默认的选项,如果想要删除父表的记录时,而在子表中有关联该父表的记录,则不允许删除父表中的记录;
- NOACTION:同 RESTRICT效果一样,也是首先先检查外键;
- CASCADE:父表delete、update的时候,子表会delete、update掉关联记录;
- SET NULL:父表delete、update的时候,子表会将关联记录的外键字段所在列设为null,所以注意在设计子表时外键不能设为not null;
3、查询操作
查找是数据库操作中一个非常重要的技术。查询一般就是使用filter、exclude以及get三个方法来实现。我们可以在调用这些方法的时候传递不同的参数来实现查询需求。在ORM层面,这些查询条件都是使用field+__+condition的方式来使用的。
查询条件
exact
使用精确的=进行查找。如果提供的是一个None,那么在SQL层面就是被解释为NULL.
from django.shortcuts import render
from django.http import HttpResponse
from .models import Article, Category
from django.db import connection
# ORM查询数据库中操作
def find_data(request):
# article = Article.objects.get(id__exact=1)
# 打印SQL原生语句
# print(connection.queries)
# article = Article.objects.get(pk__exact=1)
# print(article)
# 使用get查询数据,如果数据不存在,会报错
# article = Article.objects.get(pk__exact=None)
# 采用filter查询数据,返回的是QuerySet模型对象
article = Article.objects.filter(pk__exact=None)
print(article)
# 打印SQL原生语句
print(article.query)
return HttpResponse("find")
article.query,可以得到Django执行的SQL语句。但是只能作用于QuerySet对象上。
iexact
使用like进行查找.(精确查找,不是模糊查询)
# like查询,模糊查询,但是在SQL原生语句中没有添加 %查找名称% 所以没有模糊查询的效果,而是精确查找,下面介绍的contains字段才是模糊查询
article = Article.objects.get(id__iexact=1)
print(connection.queries)
article = Article.objects.filter(id__iexact=1)
print(article.query)
article = Article.objects.filter(title__iexact='hello world')
那么以上的查询就等价于以下的SQL语句:
select * from article where title like 'hello world';
注意上面这个sql语句,因为在MySQL中,没有一个叫做ilike的。所以exact和iexact的区别实际上就是LIKE和=的区别,在大部分collation=utf8_general_ci情况下都是一样的(collation是用来对字符串比较的)
contains
大小写敏感,判断某个字段是否包含了某个数据。(模糊查询)
articles = Article.objects.filter(title__contains='hello')
在翻译成SQL语句为如下:
select * where title like binary '%hello%';
要注意的是,在使用contains的时候,翻译成的sql语句左右两边是有百分号的,意味着使用的是模糊查询。而exact翻译成sql语句左右两边是没有百分号的,意味着使用的是精确的查询。
icontains
大小写不敏感的匹配查询。(模糊查询)
articles = Article.objects.filter(title__icontains='hello')
在翻译成SQL语句为如下:
select * where title like '%hello%';
in
提取那些给定的field的值是否在给定的容器中。容器可以为list、tuple或者任何一个可以迭代的对象,包括QuerySet对象。
articles = Article.objects.filter(id__in=[1,2,3])
以上代码在翻译成SQL语句为如下:
select *from articles where id in (1,2,3)
当然也可以传递一个QuerySet对象进去。
# 查找标题为hello的文章分类
articles = Article.objects.filter(title__icontains="hello")
# article 就是模型Article的小写,反向引用
category = Category.objects.filter(article__in=articles)
# 查找文章ID为1,2,3的文章分类
category = Category.objects.filter(article__id__in=[1,2,3])
根据关联的表进行查询
想要获取文章标题中包含"hello"的所有的分类。
# 查询获取文章标题中包含"hello"的所有的分类。
categories = Category.objects.filter(article__title__contains="hello")
categories = Category.objects.filter(article__title__icontains="hello")
比较运算
gt
某个field的值要大于给定的值。
# 将所有id大于4的文章全部都找出来。
articles = Article.objects.filter(id__gt=4)
将翻译成以下SQL语句:
select * from articles where id > 4;
gte
类似于gt,是大于等于。
lt
类似于gt是小于。
lte
类似于lt,是小于等于。
range
判断某个field的值是否在给定的区间中。
# range范围查询 查询文章id为1-3之间的文章
article = Article.objects.filter(id__range=(1,3))
print(article)
start_date = datetime(year=2019, month=12, day=1)
end_date = datetime(year=2019, month=12, day=30)
# creat_time字段范围查询
date_range = Common.objects.filter(creat_time__range=(start_date,end_date))
print(date_range)
以上代码的意思是提取所有发布时间在2019/12/1到2019/12/29当天之间的文章。
将翻译成以下的SQL语句:
SELECT `user_common`.`id`, `user_common`.`content`, `user_common`.`pid`, `user_common`.`test_date` FROM `user_common` WHERE `user_common`.`test_date` BETWEEN 2019-12-01 02:00:00 AND 2019-12-30 02:00:00。
注意:MYSQL是没有时区的概念的,Django框架才有,需要下载MYSQL支持时区文件,参考:
默认情况下MySQL不装载时区,自动采用系统时区。
windows下装载时区的办法:
- 从http://dev.mysql.com/downloads/timezones.html页面下载时区文件;
- 将压缩包中的文件(.frm、.MYD和.MYI文件)放到MySQL安装目录下的data目录下的mysql目录中,记得操作时退出MySQL,否则会失败。
- 重启MySQL。