Django模型层

Django模型层

这里所说的Django模型层,就是应用下面的models.py中的东西

1. ORM简介

ORM功能就是将数据库SQL语句映射为python语句。相当于用python语法写出SQL语法的效果
实现过程:ORM –》pymysql –》mysql –》数据库
优点:数据库迁移更容易,底层不同类型数据库不会对python代码有影响
缺点:效率不如直接写SQL快,经过一个翻译的过程。只能对表操作,不能对数据库进行操作

2. ORM使用

2.1 Django配置数据库信息

在setting.py文件下找到DATABASES列表

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',  #代表数据库引擎
        'NAME': "manytables",  #代表相应的数据库(该数据库必须存在)
        'USER':"root",    #代表数据库用户名
        'PASSWORD':"",    #代表数据库密码
        'HOST':"127.0.0.1",  #代表数据库ip
        'PORT':"3306",      #代表数据库端口
    }
}

如果我们要使用mysql,必须在setting.py或者是项目下init.py中导入PyMySQL

import pymysql
pymysql.install_as_MySQLdb()

2.2 创建表

在ORM中,创建表模型的方法是在models.py下面创建一个相应的类,用类来表示sql中的表
示例:

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()
    pub_date = models.DateField()

创建完表的类必须使用数据库迁移命令(在命令行中使用)

python manage.py makemigrations
python manage.py migrate

当修改表添加字段,再次使用命令会提示让我们提供一些值给已存在的记录
如下:

这时候我们需要给添加的字段设置默认值
例如:

read_num = models.IntegerField(default=0)
2.21 字段
SQL中的字段ORM字段注意事项
varchar,char字符型CharField必须有一个maxlength参数,用来表示最大字符数
int整数型IntegerField
float浮点型FloatField必须提供两个参数,一个是max_digits代表总位数,一个是decimal_places代表小数位数
auto_increment约束条件AutoField可选primary_key参数设置为true时,将该字段设置为主键
MYSQL没有布尔类型,通常用tinyint(1)BooleanField管理员用checkbox来表示
DateDateField日期字段,可选参数auto_now自动记录对象被保存时字段,auto_now_add自动记录的是首次被创建的时间

注意:
+ 如果不指定主键,系统会自动添加主键
+ DateTimeField字段功能同Date

ORM新增字段功能
TextField管理员用textarea来表示
EmailFIeld检查邮箱合法性,不接受maxlength参数
ImageField存储图片,可选参数height_fieldwidth_field
FileField存储文件,必须有upload_to参数

略。。。

注意:每个表中都可以使用pk字段代表主键

2.22 参数
参数作用
null该值为空,默认为false,如果将其设置为True,将会以Null存储
blank为True时,允许不填该字段,为False时就必须要填
default设置默认值,创建对象时调用
primary_key为True时,设置该字段为主键,Django默认会将一个IntegerField设置为主键
unique为true时,该字段中的值唯一
choices传入一个列表或元组,给字段提供选项,表单使用时会出现选择框,内容为choices中的内容

2.3 单表操作

表对象下的objects类封装了增删改查所有的功能

2.31 创建记录
方式一:通过objects类

Publish.objects.create(nid=1,name="ha",city="beijin",email="123@163.com")

方式二:直接实例化类对象
publish_obj = Publish(nid=1,name="ha",city="beijin",email="123@163.com")
publish_obj.save()

注意:实例化后必须使用save函数

2.32 查询记录
查询API功能
all()查询所有结果,返回queryset对象
filter(**kwargs)过滤,相当于SQL中when字段
get(**kwargs)返回查询出有且只有一条的记录
exclude(**kwargs)返回与查询条件不匹配的记录
order_by(*field)对查询结果排序(默认升序,传入字符串的字段前面加点.则表示降序排)
reverse()对查询结果反向排序
count()返回获得的记录数
first()返回第一条记录
last()返回最后一条记录
exists()查看QuerySet是否包含数据,有则返回true(查询结果是否存在)
values(*field)相当于SQL中select和from之间的条件,查询QuerySet每个记录的指定字段
values_list(*field)功能与values相似,返回的是元组,values返回的是列表
distinct()相当于SQL中的distinct关键字,去重(一般配合value使用)

注意:如果要显示全部字段使用对象下的all()函数,通常all()函数可以省略

基于双下划线的模糊查询

传入变量名后缀__**形式

后缀示例作用
__ltPublish.objects.filter(nid__lt=3)过滤出nid大于三的记录
__gtPublish.objects.filter(nid__gt=3)过滤出nid小于三的记录
__startswithPublish.objects.filter(name__startswith="li")过滤出name字段以li开头的记录
__containsPublish.objects.filter(name__contains="li")过滤出name字段包含li字符串的记录
__icontainsPublish.objects.filter(name__icontains="li")过滤出name字段包含li字符串的记录(不区分大小写)
__inPublish.objects.filter(name__in=["zs","ls","we"])过滤出name字段等于zslswe的记录
__yearPublish.objects.filter(pub_date__year=2018)过滤出pub_date字段中年份为2018的记录(该字段必须为Date)
__mouthPublish.objects.filter(pub_date__mouth=2)过滤出pub_date字段中月份为2的记录(该字段必须为Date)
__rangePublish.objects.filter(nid__range=[3,5])过滤出nid在3-5之间的记录
2.33 修改记录

过滤出的结果链式调用update()函数
Publish.objects.filter(nid = 1).update(name = "wb")
将nid为1的记录的name字段修改为wb

2.34 删除记录

直接在过滤出的结果链式调用delete()函数
Publish.objects.filter(nid = 1).delete()
删除nid为1的记录

2.4 多表操作

多表操作分为三种情况:一对一,一对多,多对多

2.41 创建表记录

对于一对一情况,我们需要先创建一个字段,使用OneToOneField建立关系,to代表需要建立关系的表,如果不指定to_field参数,默认绑定表的主键。必须要有一个on_delete代表是否同步删除
示例:

class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()

    # 与AuthorDetail建立一对一的关系
    authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)

class AuthorDetail(models.Model):

    nid = models.AutoField(primary_key=True)
    birthday=models.DateField()
    telephone=models.BigIntegerField()
    addr=models.CharField( max_length=64)

对于一对多情况,我们需要先创建一个字段,使用ForeignKey建立关系,添加外键
示例:

class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)

    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)

对于多对多情况,我们需要先创建是一个字段,使用ManyToManyField来建立关系,

class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)

    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors=models.ManyToManyField(to='Author',)

创建完表的类必须使用数据库迁移命令(在命令行中使用)

python manage.py makemigrations
python manage.py migrate

注意:
1.创建成功后,会在数据库里生成相应的表,表的格式为应用名__表名
例如:manytables__Book
而多对多产生的第三张表名为 应用名__表1名__表2名
2.外键字段,在表中会显示“外键_id”来命名
例如:publish_id

2.42 添加表记录
多对一/一对一添加表记录

因为有一个外键,添加表记录的方法有两种
方式一:直接给表的外键字段赋值
Book.objects.create(nid=1,title="cprimer",publishDate="2012-12-3",price=30,publish_id=1)
Book表与Publish表为多对一的关系,publish_id为其外键

方式二:给外键对象赋值

publish_obj=Publish.objects.create(nid=1,name="ha",city="beijin",email="123@163.com")
Book.objects.create(nid=1,title="cprimer",publishDate="2012-12-3",price=30,publish=publish_obj)

直接将Publish对象赋值给publish

多对多添加表记录

多对多关系,每张表没有外键,但第三张表有其关系,这里用固定的API
添加多对多关系方法:
对象名.绑定字段名.add()
注意:
1.使用在类中多对多方法时,不会给该表添加格外的字段,而是生成第三张表,来表示两者关系
2.我们可以使用添加多对多字段的表的对象,调用其下面的添加多对多字段名的add()方法

add()方法解析,添加多对多记录
示例:
book表与author为多对多关系,且book表调用ManyToMany方法

book_obj.authors.add(author1_obj,author2_obj)  #author1_obj,author2_obj为author对象
book_obj.authors.add(1,2,3)   #1,2,3为对象id

remove(),clear()删除多对多记录
示例:

book_obj.authors.remove(2)  #移除第三张表4,2关系
book_obj.authors.remove(12)  #移除第三张表4,2关系和4,1关系
book_obj.authors.clear() #清空所有第三张表中所有与4相关联的记录

注意:
+ 从对象中访问外键对象,使用book_obj.publish就可以从book_obj对象访问publish;而使用book_obj.pulish_id就可以访问绑定的外键
+ 创建外键时,django会自动在外键名后面加_id,例如创建一个外键名为publish,而使用的外键字段是publish_id

2.43 基于对象的跨表查询(子查询)

正向查询:关联属性在A中,从A表查B表数据
逆向查询:关联属性在A中,从B表查A表数据

一对多

正向查询按字段,反向查询按表名小写_set
正向查询示例:
查询金瓶梅出版社的名字

book_obj=book.objects.filter(title="金瓶梅").first()
book_obj.publish.name

反向查询示例:
查询人民出版社出版过的书籍名称

publish_obj=Publish.objects.filter(name="人民出版社")
publish.book_set.all()

总结:关联属性在所查的表中时,直接使用
基对象.关联对象.关联对象属性
来查询所需要的值;反之,使用
基对象.关联对象_set.关联对象属性
来查询所需要的值

多对多

正向查询示例:
查询金瓶梅作者的名称

book_obj = Book.objects.filter(title="金瓶梅").first()
book_obj.authors.all().value('name')  

反向查询示例:
找alex出版过的所有书籍名称

author_obj=Author.objects.filter(name="alex").first()
book_list=author_obj.book_set.all()

多对多与多对一查询方法一致
注意:book_obj.authors.all().value('name')等同于book_obj.authors.value('name')

一对一

正向查询示例:
查找alex的手机号

alex=Author.objects.filter(name="alex").first()
alex.authordetail.telephone  

查询手机号为110的作者的名字

AuthorDetail.objects.filter(telephone="110").first().author.name

总结:一对一查询无论正向查询还是反向查询,都直接查询对象即可

2.44 基于双下划线的跨表查询(join查询)
一对多

查询金瓶梅出版社的名字
方式一:正向查询
Book.objects.filter(title="金瓶梅").values("publish__name")
方式二:反向查询
Publish.objects.filter(book_title="金瓶梅").values("name")

多对多

查询金瓶梅作者的名称
方式一:正向查询
Book.objects.filter(title="金瓶梅").values("authors__name")
方式二:反向查询
author.objects.filter(book_title="金瓶梅").values("name")

一对一

查找alex的手机号
方式一:正向查询
author.objects.filter(name="alex").values("authordetail__telephone")
方式二:反向查询
authordetail.objects.filter(author_name="alex").value("telephone")

总结:
+ values()等同于select filter()等同于where
+ 如果想要查询的字段在关联表,则使用表名小写__字段来进行跨表查询操作

2.45 连续跨表查询

查询手机号以110开头的作者出版过的所有书籍名称以及对应出版社名称
定基表:作者,书籍,出版社
方式一:book表为基表
Book.objects.filter(authors__authordetail__telephone__startswith="110").value("name","publish__name")
注意:book表连接无关的authordetail表,需要连续跨表

方式二:以author表为基表
Author.objects.filter(authordetail_telephone__startswith="110").value("book__title","book__publish__name")
总结:
连续跨表查询其实方法也一样,先定一个基表,然后找出基表与查询条件表的关系,跨表用__连接

2.46 聚合查询

查询平均价格,最大值,最小值
首先,必须先引入相关模块

from django.db.models import Avg,Max,Min, Count
Book.objects.all().aggregate(Avg("price"))

然后使用aggregate()聚合函数
示例:
查询所有书籍的平均价格,最高价格,最低价格(average)
Book.objects.all().aggregate(Avg("price"),Max("price"),Min("price"))

2.47 分组查询
单表分组查询

annotate()为分组函数
示例:
查询每一个部门名称以及员工平均薪水
Emp.objects.values("dep").annotate(avg_salary=Avg("salary"))
总结:
单表模型.objects.values("group by的字段")。annotate(聚合函数("统计字段"))

多表分组查询

示例一:
查询每一个出版社的名称以及出版的书籍个数

Publish.objects.value("name").annotate(c=Count("book__title"))

默认显示name和c字段,如果要对分组后控制显示字段,则在后面加入value()
Publish.objects.value("nid").annotate(c=Count("book__title")).value("name","c")

注意:
+ 分组后可以显示任意字段,只是默认显示分组字段和聚合函数字段
+ value里面是什么,就按什么group by ,values()里面的内容相当于select和from中间的内容
+ 可以不使用value(),使用all()函数功能也相同,都是选择该表的字段(字段唯一),对表中的字段进行分组;
例如:查询每一个出版社的名称以及出版的书籍个数
Publish.objects.all().annotate(c=Count("book_title")).values("name","email","c")
默认,all()可以省略,即可写成
Publish.objects.annotate(c=Count("book_title")).values("name","email","c")

2.48 F查询与Q查询
F()查询

F()就是将原来字段取到值,再次当参数传入
示例一:查找评论数大于阅读数的记录
Book.objects.filter(comment_num__gt=F("read_num"))
不能直接用comment_num__gt=read_num这样操作,必须在右边加一个F()

示例二:将所有书籍价格提升十块钱
Book.objects.all().update(price=F("price")+10)
不能直接用price+=10传入,必须用F()

Q()查询

查询名字为红楼梦,价格为100的书籍记录
Book.objects.filter(title="红楼梦",price=100) 等同于
Book.objects.filter(Q(title="红楼梦")&Q(price=100))

查询名字为红楼梦或价格为100的书籍记录
Book.objects.filter(Q(title="红楼梦")|Q(price=100))

Q()可以连续嵌套Q(Q(A)|Q(B))|Q(C)

符号名称作用
&与运算两者都满足
``或运算
~非运算取反运算

注意:
后面还可以跟关键字参数,但是关键字参数只能放在Q()后面
Book.objects.filter(Q(title="红楼梦"),price=100)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值