Django模型层

布满荆棘的人生 2022-05-13 02:28 366阅读 0赞
  • Django模型层

      1. ORM简介
      1. ORM使用

        • 2.1 Django配置数据库信息
        • 2.2 创建表

          • 2.21 字段
          • 2.22 参数
        • 2.3 单表操作

          • 2.31 创建记录

            • 方式一:通过objects类
            • 方式二:直接实例化类对象
          • 2.32 查询记录

            • 基于双下划线的模糊查询
          • 2.33 修改记录
          • 2.34 删除记录
        • 2.4 多表操作

          • 2.41 创建表记录
          • 2.42 添加表记录

            • 多对一/一对一添加表记录
            • 多对多添加表记录
          • 2.43 基于对象的跨表查询(子查询)

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

            • 一对多
            • 多对多
            • 一对一
          • 2.45 连续跨表查询
          • 2.46 聚合查询
          • 2.47 分组查询

            • 单表分组查询
            • 多表分组查询
          • 2.48 F查询与Q查询

            • F()查询
            • Q()查询

Django模型层

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

1. ORM简介

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

2. ORM使用

2.1 Django配置数据库信息

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

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

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

  1. import pymysql
  2. pymysql.install_as_MySQLdb()

2.2 创建表

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

  1. 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()

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

  1. python manage.py makemigrations
  2. python manage.py migrate

当修改表添加字段,再次使用命令会提示让我们提供一些值给已存在的记录
如下:
30400
这时候我们需要给添加的字段设置默认值
例如:

  1. 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来表示
Date DateField 日期字段,可选参数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")

方式二:直接实例化类对象
  1. publish_obj = Publish(nid=1,name="ha",city="beijin",email="123@163.com")
  2. 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()函数可以省略

基于双下划线的模糊查询

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
























































后缀 示例 作用
lt Publish.objects.filter(nidlt=3) 过滤出nid大于三的记录
gt Publish.objects.filter(nidgt=3) 过滤出nid小于三的记录
startswith Publish.objects.filter(namestartswith=”li”) 过滤出name字段以li开头的记录
contains Publish.objects.filter(namecontains=”li”) 过滤出name字段包含li字符串的记录
icontains Publish.objects.filter(nameicontains=”li”) 过滤出name字段包含li字符串的记录(不区分大小写)
in Publish.objects.filter(namein=[“zs”,”ls”,”we”]) 过滤出name字段等于zslswe的记录
year Publish.objects.filter(pub_dateyear=2018) 过滤出pub_date字段中年份为2018的记录(该字段必须为Date)
mouth Publish.objects.filter(pub_datemouth=2) 过滤出pub_date字段中月份为2的记录(该字段必须为Date)
range Publish.objects.filter(nidrange=[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代表是否同步删除
示例:

  1. class Author(models.Model):
  2. nid = models.AutoField(primary_key=True)
  3. name=models.CharField( max_length=32)
  4. age=models.IntegerField()
  5. # 与AuthorDetail建立一对一的关系
  6. authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
  7. class AuthorDetail(models.Model):
  8. nid = models.AutoField(primary_key=True)
  9. birthday=models.DateField()
  10. telephone=models.BigIntegerField()
  11. addr=models.CharField( max_length=64)

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

  1. class Book(models.Model):
  2. nid = models.AutoField(primary_key=True)
  3. title = models.CharField( max_length=32)
  4. publishDate=models.DateField()
  5. price=models.DecimalField(max_digits=5,decimal_places=2)
  6. # 与Publish建立一对多的关系,外键字段建立在多的一方
  7. publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)

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

  1. 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',)

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

  1. python manage.py makemigrations
  2. 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为其外键

方式二:给外键对象赋值

  1. publish_obj=Publish.objects.create(nid=1,name="ha",city="beijin",email="123@163.com")
  2. 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方法

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

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

  1. book_obj.authors.remove(2) #移除第三张表4,2关系
  2. book_obj.authors.remove(12) #移除第三张表4,2关系和4,1关系
  3. 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
正向查询示例:
查询金瓶梅出版社的名字

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

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

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

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

多对多

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

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

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

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

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

一对一

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

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

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

  1. 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 聚合查询

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

  1. from django.db.models import Avg,Max,Min, Count
  2. 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(聚合函数("统计字段"))

多表分组查询

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

  1. 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)

























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

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

发表评论

表情:
评论列表 (有 0 条评论,366人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Django模型

    Django 模型 Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。 Django 为这些数据库提供了

    相关 Django模型

    Django模型 Django对各种数据库提供了很好的支持。包括MySQL,SQLite,Orcale等。 Django为这些数据库提供了统一的调用api。可以根据不同

    相关 Django 模型

    Django 模型是与数据库相关的,与数据库相关的代码一般写在 models.py 中,Django 支持 sqlite3, MySQL, PostgreSQL等数据库,只需要