Django框架学习——8—(外键和表关系、外键删除操作、查询操作)

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/12019/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下装载时区的办法:

  1. 从http://dev.mysql.com/downloads/timezones.html页面下载时区文件;
  2. 将压缩包中的文件(.frm、.MYD和.MYI文件)放到MySQL安装目录下的data目录下的mysql目录中,记得操作时退出MySQL,否则会失败。
  3. 重启MySQL。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值