Django的日常-模型层(1)

模型层

模型层其实就是我们应用名下的models.py文件,我们在里面写入想要创建的表的表结构,以类的形式表示出来,然后通过django的ORM来实现表的创建,以及表的增删改查等.

django测试环境

不是正式开发项目的话,其实我们不必要一定按正式的流程来,又要建html,又要写urls,写views,因为我们在学习模型层的时候其实只需要通过ORM来对数据库进行操作,所以我们大可以搭建一个django的测试环境,以此来实验我们的一些命令,创建测试环境的步骤如下:

# 我们需要在应用名下的test.py里面写入如下语句来搭建测试环境

#test.py

import os

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "创建的项目名字.settings")
import django
django.setup() #在下方写需要测试的对数据库操作的代码即可

另外有一个小点,就是我们在通过ORM对数据库操作的时候,如果我们想看到ORM转换过程中的sql语句,需要在settings.py进行以下的配置

# settings.py ,在最下方加入这个配置项即可
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level': 'DEBUG',
},
}
}

ORM查询

ORM的概念我们在前文已经介绍过了,下面我们来看ORM对于数据库的一些具体操作

在写ORM语句之前我们首先要有一个数据库,以及配置好当前django所用的数据库,步骤如下

# 首先,删除或者注释掉settings.py里面的DATABASES选项,然后手动加一个本地数据库的信息

# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysql1',
'USER': 'root',
'PASSWORD': "root",
'HOST': '127.0.0.1',
'PORT': 3306,
'CHARSET': 'utf8'
}
}
# 设置过这个配置项之后我们还需要在项目名文件夹下的__init__.py里面写入如下两行代码,以便于让django默认的数据库连接方式从MySQLdb转换成pymysql
import pymysql
pymysql.install_as_MySQLdb()

然后我们需要在models.py里面写自己想要创建的表结构

'''我们以书店为例,需要创建的表为,书籍表,作者表,作者详情表,出版社表,其中
书籍-出版社,一对多
作者-作者详情,一对一
书籍-作者,多对多
''' # models.py
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField(auto_now_add=True)
"""
auto_now:每次修改数据的时候 都会自动更新时间
auto_now_add:在创建数据的时候 会自动将当前时间记录下来
后期如果你不人为修改的话 数据不变
""" # 书籍与出版社 是一对多关系
publish = models.ForeignKey(to='Publish')
# 书籍与作者 是多对多
authors = models.ManyToManyField(to='Author')
"""
authors虚拟字段
1.告诉orm自动帮你创建第三张关系表
2.orm查询的时候 能够帮助你更加方便的查询
""" class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64) class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
# author_detail = models.ForeignKey(unique=True,to='AuthorDetail')
author_detail = models.OneToOneField(to='AuthorDetail') class AuthorDetail(models.Model):
phone = models.BigIntegerField()
addr = models.CharField(max_length=64)

单表查询

单表查询,顾名思义就是在一张表内进行数据查询,下面的语句就是单表查询所常用的一些方法

# 对数据库的操作无外乎就是增删改查,下面逐一介绍,下面的语句都是写在test.py里面,就是我们前面搭建好的测试环境里面
# test.py from 应用名 import models # 增
# 方式一,直接调用create添加数据
models.Book.objects.create(title='jpm',price=123.23,publish_date='2019-10-24')
# 方式二,生成对象,以对象.save的方式保存数据
from datetime import date
ctime = date.today() # 时间格式是可以直接使用date的日期的
book_obj = models.Book(title='sgyy',price=666.66,publish_date=ctime)
book_obj.save() # 改
# 方式一,以update的方式更新数据
models.Book.objects.filter(pk=1).update(price=999.66)
# 方式二,生成对象,直接修改,然后用.save保存
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.title = '不符合社会主义核心价值观'
book_obj.save() # 删除
# 筛选出符合条件的记录直接delete()即可
models.Book.objects.filter(pk=1).delete() # 查
# 1.all() 查询所有
res = models.Book.objects.all()
# 惰性查询,惰性查询的概念在于,如果我们只是定义了这个语句的话,他并不会执行,只有在调用它,比如打印的时候,这个语句才会真正运行,查询的这么多方法里面大都是惰性查询
print(res)
for i in res:
print(i.title) # 2.filter() 按照条件查询,会匹配到所有符合条件的记录,且filter可以无限叠加
res = models.Book.objects.filter(pk=2)
print(res) # 3.get() 可以拿到数据对象本身,但是如果符合条件的记录不存在,会报错,所以不推荐使用 # 4.first() 拿第一个
res = models.Book.objects.all()
print(res)
print(res.first()) # 5. last() 拿最后一个
res = models.Book.objects.all()
print(res)
print(res.last()) # 6.exclude() 除此之外,即符合条件的记录不取,取剩余的全部记录
res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4)
print(res) # 7.values 返回数据的格式是列表套字典
res = models.Book.objects.values('title')
for r in res:
print(r.get('title')) # 8.values_list 列表套元组
res = models.Book.objects.values_list('title')
print(res) # 9.count() 统计数据的个数
res = models.Book.objects.count()
res1 = models.Book.objects.all().count()
print(res,res1) # 10.distinct() 去重
"""去重:数据必须是一模一样的情况下才能去重,包括主键,尤其要注意"""
res = models.Book.objects.all().distinct()
res1 = models.Book.objects.values('title','price').distinct()
print(res1) # 11.order_by() 以某个标准排序
res = models.Book.objects.order_by('price') # 默认是升序
res1 = models.Book.objects.order_by('-price') # 加负号就是降序
print(res)
print(res1) # 12.reverse() 注意,前面必须是先经过排序后的数据才可以反转,否则反转会无效,数据顺序不会发生变化
res = models.Book.objects.order_by('price').reverse()
print(res) # 13.exists() 排除符合条件的记录,不太常用
res = models.Book.objects.filter(pk=1).exists()
print(res) # 查询还有一类比较好用的方法,即双下划线的方式
# 双下划线可以实现很多非常神奇的筛选方法,比如大于小于,或者是限定范围,还支持模糊匹配 # 1. __gt和__gte,gt是大于,gte是大于等于
res1 = models.Book.objects.filter(price__gt=300)
res2 = models.Book.objects.filter(price__gte=300)
# 上面的语句分别可以查询得到价格大于300和大于等于300的图书的对象 # 2. __lt和__lte,lt是小于,lte是小于等于
res1 = models.Book.objects.filter(price__lt=300)
res2 = models.Book.objects.filter(price__lte=300)
#上面语句可以查询得到价格小于300和小于等于300的所有图书的对象 # 3. __in和__range,in是否在其内,后面通常为容器类型,range,是否在一个范围内,后面通常跟元组表示范围
res = models.Book.objects.filter(price__in=[100,200,456,]) #筛选范围仅仅是列表内的这几个值
res = models.Book.objects.filter(price__range=(100,499)) #筛选价格在100到499范围内的书,这里是顾头不顾尾的,即价格为100的书在范围内,但是价格为499的书不在范围内. # 我们知道sql语句里面的模糊匹配其实就只有like,再加上%或者_,%是任意位数的任意字符,而_是一位的任意字符 # 双下划线可以实现ORM里面的模糊匹配,常用的几个方法包括contains,icontains,startswith,endswith,year,month等等. # 1. contains 按字符模糊匹配,区分大小写
# 2. icontains 按字符模糊匹配,不区分大小写
# 3. startswith 以某个字符开头
# 4. endswith 以某个字符结尾
# 5. year 用于判定日期格式数据的年份
# 6. month 用于判断日期格式数据的月份

多表查询

上面我们介绍了单表查询的一些方法和语句,下面就来看看多表查询常用的一些方法

我们依然从增删改查四个方面来分析多表间的操作:

# 多对多表关系之间修改字段的四个方法,add,set,remove以及clear

# 1. add()添加,括号内可以填多个值,会生成多条记录,其实修改的是多对多的那个关系表,add的括号里面可以传数字,也可以直接传一个对象,ORM会自动把该对象的主键的值取出来,传给add使用,比如

	# 传数字
book_obj = models.Book.objects.filter(pk = 1).first()#这里取出一个书籍对象
book_obj.authors.add(1)# 书籍对象.作者,其实得到的就是两者的关系表
# 传对象
author_obj = models.Author.objects.filter(pk=1).first()
book_obj.authors.add(author_obj) # 2. set() 修改,用法和add相似,也支持多个值,支持传数字和对象,不同的是括号里要是一个可迭代对象,也就是说括号内不能为一个单独的值,而应该是列表,元素,字典或者集合这种可迭代对象
# 传数字
book_obj = models.Book.objects.filter(pk = 3).first()
book_obj.authors.set([1,])
# 传对象
author_obj = models.Author.objects.filter(pk=1).first()
book_obj.authors.set((author_obj,))#这里是元组,注意,元组如果只有一个值,要加逗号,不然会报错 # 3. remove(),移除某条记录,可以传数字和对象,支持传多个值
# 传数字
book_obj = models.Book.objects.filter(pk = 3).first()
book_obj.authors.remove(2)
# 传对象
author_obj = models.Author.objects.filter(pk=1).first()
book_obj.authors.remove(author_obj)
# 4. clear(),清空,括号内不需要任何值,可以直接清空当前关系表
book_obj = models.Book.objects.filter(pk=2).first()
book_Obj.authors.clear() # 这里会拿到作者和书籍的关系表,然后把book表里主键值为2对应的所有数据清空

因为实际生产环境中其实还是多表用的比较多,毕竟很多数据都不是放在一起的,这时候我们就需要通过联表或者是通过子查询的方式来解决数据查询的问题,所以ORM提供给我们两个更好的多表查询的方法,其原理依然还是联表和子查询,不过其叫法不同

  1. 基于对象的跨表查询其实就是子查询
  2. 基于双下划线的跨表查询其实就是联表查询.

这里我们还要清楚一个正向查询和反向查询的概念,即我们从外键所在的表向外面的表查询的时候,叫做正向查询,反过来就叫做反向查询.

'''基于对象的跨表查询'''
#顾名思义,我们要通过筛选并生成出一个对象,然后从这个对象连到其他表,再查询取值,比如: # 正向查询
# 单个值
book_obj = models.Book.objects.filter(title='python').first()
print(book_obj.publish.name)#这里用书籍对象直接.出版社,此时其实就已经到了publish表里面,然后直接.name就可以拿到相对应的值,这里因为书籍对应的出版社都是单个值,所以可以直接取值 # 多个值
book_obj = models.Book.objects.filter(pk = 1).first()
print(book_obj.authors) # 我们可以看到这里返回结果是 应用名.Author.None,这并不意味着我们的语句写错了,而是返回的结果不是单个值,我们取不到
print(book_obj,authors.all())# 所以如果查询到结果是多个值,要在后面加.all(),才能正常看到返回结果 # 反向查询
# 单个值
author_detail_obj = models.AuthorDetail.objects.filter(pk=1).first()
print(author_detail_obj.author)
print(author_detail_obj.author.name)
# 多个值
publish_obj = models.Publish.objects.filter(pk = 1).first()
print(publish_obj.book_set) # 这里结果是 应用名.Book.None,是不是很熟悉?对,要加.all()
print(publish_obj.book_set.all())
#总结下来就是,反向查询时,当查询结果是多个值的时候,需要加_set.all()在后面,而查询结果只有一个值的话不需要加这个
'''基于双下划线的跨表查询'''
# 上文中我们说过,基于双下划线的跨表查询其实就是联表查询,那么在原生sql里面联表方式有几种呢?四种,即左联left join,右联right join,内联inner join,全联 union.在当前的ORM里面我们不必关心这些联表方式,内部会帮我们做处理,我们需要做的只是理清楚查询逻辑,或者说其实我们只需要认清楚是正向查询还是反向查询就可以了. # 和双下划线相匹配使用的方法就是.values()
res = models.Book.objects.filter(pk=1).values('publish__name')
print(res)
# 上面以书籍的主键来寻找到出版社的名字是正向查询,那么与之对应的反向查询如下
res = models.Publish.objects.filter(book__pk=1),values('name')
print(res)

Django的日常-模型层(1)的更多相关文章

  1. Django的日常-模型层(2)

    目录 Django的日常-模型层(2) 几种常用的查询方式 聚合查询 分组查询 F和Q查询 查询优化相关 orm中常见字段 choices参数 orm的事务操作 Django的日常-模型层(2) 几种 ...

  2. Django的日常-路由层

    目录 Django的日常-2 路由层 有名分组和无名分组 反向解析 路由的分发 Django的日常-2 路由层 我们之前已经接触过路由层,只是我们可能不知道他叫这个名字,实际上在Django里面路由层 ...

  3. Django学习之模型层

    模型层 查看orm内部sql语句的方法的方法 1.如果是queryset对象,那么可以点query直接查看该queryset的内部sql语句 2.在Django项目的配置文件中,配置一下参数即可实现所 ...

  4. Django基础之模型层(02)

    1 重要概念 # 多表查询 """ 正向查询 反向查询 当前查询对象是否含有外键字段 如果有就是正向 没有无则是反向 口诀: 正向查询按外键字段 多对多需要额外再加一个. ...

  5. Django基础(3)----模型层-单表操作,多表创建

    昨日内容回顾: 1. {% include '' %} 2. extend base.html: <html> ..... ..... ..... {% block content%} { ...

  6. Django基础之模型层(下)

    聚合查询 关键字:aggregate from django.db.models import Max,Min,Sum,Count,Avg 统计所有书的平均价格 models.Book.objects ...

  7. Django基础之模型层(01)

    内容概要 查询关键字 MySQL select    from    where    group by    having    order by    distinct    limit    r ...

  8. Django模型层ORM学习笔记

    一. 铺垫 1. 连接Django自带数据库sqlite3 之前提到过Django自带一个叫做sqlite3的小型数据库,当我们做本地测试时,可以直接在sqlite3上测试.不过该数据库是小型的,在有 ...

  9. 64、django之模型层(model)--建表、查询、删除基础

    要说一个项目最重要的部分是什么那铁定数据了,也就是数据库,这篇就开始带大家走进django关于模型层model的使用,model主要就是操纵数据库不使用sql语句的情况下完成数据库的增删改查.本篇仅带 ...

随机推荐

  1. leetcode-158周赛-5223-可以攻击国王的皇后

    题目描述: 自己的提交: class Solution: def queensAttacktheKing(self, queens: List[List[int]], king: List[int]) ...

  2. leetcood学习笔记-203-移除链表元素

    题目描述: 方法:#在改pre链表时 head中的值也改变 class Solution(object): def removeElements(self, head, val): "&qu ...

  3. Servlet - Servlet相关

    1. 概念 Servlet是指任何实现了Servlet接口的类, Servlet运行于支持Java的应用服务器中, Servlet可以响应任何类型的请求, 但大多数情况下, Servlet只用来扩展基 ...

  4. shell 脚本定制与重定向

    脚本定制 . 或者 source: 读取文本文件并执行(在当前shell解释并执行) source ./ld 总用量 8 -rw-------. 1 root root 1223 10月 2 21:1 ...

  5. JavaScript中深拷贝实现

    JavaScript 中深拷贝实现   拷贝时候涉及到: 1.循环结构 2.判断数组 Array 还是对象 Object   函数实现 /** * 获取满足条件的数组中的第一个元素 * @param ...

  6. NOIp2018集训test-9-19(am&pm)

    AM 这是一套在长沙考过而且我能记得全部正解的题,然后期望得分300实际得分155. T1 很套路,随便搞(我当年是怎么花大半场时间写T1并且写出现在两倍长的代码的??) //Achen #inclu ...

  7. NX二次开发-获取按钮的ID UF_MB_ask_button_id

    NX9+VS2012 1.打开D:\Program Files\Siemens\NX 9.0\UGII\menus\ug_main.men 找到装配和PMI,在中间加上一段 TOGGLE_BUTTON ...

  8. jquery preventDefault()事件

    定义和用法 preventDefault() 方法阻止元素发生默认的行为(例如,当点击提交按钮时阻止对表单的提交). 语法 event.preventDefault() 参数 描述 event 必需. ...

  9. Date转换为LocalDateTime

    一.在Java 8中将Date转换为LocalDateTime 方法1: 将Date转换为LocalDatetime,我们可以使用以下方法: 1.从日期获取ZonedDateTime并使用其方法toL ...

  10. [kuangbin带你飞]专题一 简单搜索 - K - 迷宫问题

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #i ...