Django-07-Model操作
一、数据库的配置
1. 数据库支持
django默认支持sqlite、mysql、oracle、postgresql数据库
<1> sqlite
django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3
<2> mysql
引擎名称:django.db.backends.mysql
2. mysql驱动程序
- MySQLdb(mysql python)
- mysqlclient
- MySQL
- PyMySQL(纯python的mysql驱动程序)
3. setting配置
在django的项目中会默认使用sqlite数据库,在settings里有如下设置:
如果我们想要更改数据库,需要修改如下:
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', 'NAME': 'books', #你的数据库名称'USER': 'root', #你的数据库用户名'PASSWORD': '', #你的数据库密码'HOST': '', #你的数据库主机,留空默认为localhost'PORT': '3306', #你的数据库端口}
}
NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建USER和PASSWORD分别是数据库的用户名和密码。设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。然后,启动项目,会报错:no module named MySQLdb这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL所以,我们只需要找到项目名文件下的__init__,在里面写入:
import pymysql
pymysql.install_as_MySQLdb()
4. 使用pycharm连接mysql数据库
<1> 开启mysql服务
<2> 下载驱动程序
<3> 测试并连接
常见错误:
08001 时区错误
解决方法:修改时区为“+8:00”
再次连接即可
二、Django的ORM(对象关系映射)
用于实现面向对象编程语言里不同类型系统的数据之间的转换,换言之,就是用面向对象的方式去操作数据库的创建表以及增删改查等操作。
优点: 1 ORM使得我们的通用数据库交互变得简单易行,而且完全不用考虑该死的SQL语句。快速开发,由此而来。
2 可以避免一些新手程序猿写sql语句带来的性能问题。
缺点:1 性能有所牺牲,不过现在的各种ORM框架都在尝试各种方法,比如缓存,延迟加载登来减轻这个问题。效果很显著。
2 对于个别复杂查询,ORM仍然力不从心,为了解决这个问题,ORM一般也支持写raw sql。
表模型的创建
实例:我们来假定下面这些概念,字段和关系
作者模型:一个作者有姓名。
作者详细模型:把作者的详情放到详情表,包含性别,email地址和出生日期,作者详情模型和作者模型之间是一对一的关系(one-to-one)(类似于每个人和他的身份证之间的关系),在大多数情况下我们没有必要将他们拆分成两张表,这里只是引出一对一的概念。
出版商模型:出版商有名称,地址,所在城市,省,国家和网站。
书籍模型:书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many),一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many),也被称作外键。
from django.db import models
class Publish(models.Model):name = models.CharField(max_length=30, verbose_name="名称")address = models.CharField("地址", max_length=50)city = models.CharField('城市',max_length=60)state_province = models.CharField(max_length=30)country = models.CharField(max_length=50)website = models.URLField()class Meta:verbose_name = '出版商'verbose_name_plural = verbose_namedef __str__(self):return self.nameclass Author(models.Model):name = models.CharField(max_length=30)def __str__(self):return self.nameclass AuthorDetail(models.Model):sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),))email = models.EmailField()address = models.CharField(max_length=50)birthday = models.DateField()author = models.OneToOneField(Author)class Book(models.Model):title = models.CharField(max_length=100)authors = models.ManyToManyField(Author)publish = models.ForeignKey(Publish)publication_date = models.DateField()price=models.DecimalField(max_digits=5,decimal_places=2,default=10)def __str__(self):return self.title
注意1:记得在settings里的INSTALLED_APPS中加入'app01',然后再同步数据库。
注意2: models.ForeignKey("Publish") & models.ForeignKey(Publish)
分析代码:
<1> 每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。
<2> 每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。
<3> 模型之间的三种关系:一对一,一对多,多对多。
一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;
一对多:就是主外键关系;(foreign key)
多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)
模型常用的字段类型参数
<1> CharField#字符串字段, 用于较短的字符串.#CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.<2> IntegerField#用于保存一个整数.<3> FloatField# 一个浮点数. 必须 提供两个参数:## 参数 描述# max_digits 总位数(不包括小数点和符号)# decimal_places 小数位数# 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:## models.FloatField(..., max_digits=5, decimal_places=2)# 要保存最大值一百万(小数点后保存10位)的话,你要这样定义:## models.FloatField(..., max_digits=19, decimal_places=10)# admin 用一个文本框(<input type="text">)表示该字段保存的数据.<4> AutoField# 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; # 自定义一个主键:my_id=models.AutoField(primary_key=True)# 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.<5> BooleanField# A true/false field. admin 用 checkbox 来表示此类字段.<6> TextField# 一个容量很大的文本字段.# admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框).<7> EmailField# 一个带有检查Email合法性的 CharField,不接受 maxlength 参数.<8> DateField# 一个日期字段. 共有下列额外的可选参数:# Argument 描述# auto_now 当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳.# auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.#(仅仅在admin中有意义...)<9> DateTimeField# 一个日期时间字段. 类似 DateField 支持同样的附加选项.<10> ImageField# 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field,# 如果提供这两个参数,则图片将按提供的高度和宽度规格保存.
<11> FileField# 一个文件上传字段.#要求一个必须有的参数: upload_to, 一个用于保存上传文件的本地文件系统路径. 这个路径必须包含 strftime #formatting, #该格式将被上传文件的 date/time #替换(so that uploaded files don't fill up the given directory).# admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) .#注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤:#(1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. # (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 # WEB服务器用户帐号是可写的.#(2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django# 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). # 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField # 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径.<12> URLField# 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且# 没有返回404响应).# admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)<13> NullBooleanField# 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项# admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.<14> SlugField# "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs# 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50. #在# 以前的 Django 版本,没有任何办法改变50 这个长度.# 这暗示了 db_index=True.# 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate # the slug, via JavaScript,in the object's admin form: models.SlugField# (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.<13> XMLField#一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径.<14> FilePathField# 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的.# 参数 描述# path 必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. # Example: "/home/images".# match 可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名. # 注意这个正则表达式只会应用到 base filename 而不是# 路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif.# recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录.# 这三个参数可以同时使用.# match 仅应用于 base filename, 而不是路径全名. 那么,这个例子:# FilePathField(path="/home/images", match="foo.*", recursive=True)# ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif<15> IPAddressField# 一个字符串形式的 IP 地址, (i.e. "24.124.1.30").
<16> CommaSeparatedIntegerField# 用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.
其他字段
BigAutoField(AutoField)- bigint自增列,必须填入参数 primary_key=True注:当model中如果没有自增列,则自动会创建一个列名为id的列from django.db import modelsclass UserInfo(models.Model):# 自动创建一个列名为id的且为自增的整数列username = models.CharField(max_length=32)class Group(models.Model):# 自定义自增列nid = models.AutoField(primary_key=True)name = models.CharField(max_length=32)SmallIntegerField(IntegerField):- 小整数 -32768 ~ 32767PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正小整数 0 ~ 32767IntegerField(Field)- 整数列(有符号的) -2147483648 ~ 2147483647PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正整数 0 ~ 2147483647BigIntegerField(IntegerField):- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807GenericIPAddressField(Field)- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6- 参数:protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"UUIDField(Field)- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证TimeField(DateTimeCheckMixin, Field)- 时间格式 HH:MM[:ss[.uuuuuu]]DurationField(Field)- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型DecimalField(Field)- 10进制小数- 参数:max_digits,小数总长度decimal_places,小数位长度BinaryField(Field)- 二进制类型
Field重要参数
null 数据库中字段是否可以为空db_column 数据库中字段的列名default 数据库中字段的默认值primary_key 数据库中字段是否为主键db_index 数据库中字段是否可以建立索引unique 数据库中字段是否可以建立唯一索引unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引unique_for_month 数据库中字段【月】部分是否可以建立唯一索引unique_for_year 数据库中字段【年】部分是否可以建立唯一索引verbose_name Admin中显示的字段名称blank Admin中是否允许用户输入为空editable Admin中是否可以编辑help_text Admin中该字段的提示信息choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date如:{'null': "不能为空.", 'invalid': '格式错误'}validators 自定义错误验证(列表类型),从而定制想要的验证规则from django.core.validators import RegexValidatorfrom django.core.validators import EmailValidator,URLValidator,DecimalValidator,\MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator如:test = models.CharField(max_length=32,error_messages={'c1': '优先错信息1','c2': '优先错信息2','c3': '优先错信息3',},validators=[RegexValidator(regex='root_\d+', message='错误了', code='c1'),RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),EmailValidator(message='又错误了', code='c3'), ])
多表关系字段参数
ForeignKey(ForeignObject) # ForeignObject(RelatedField)to, # 要进行关联的表名to_field=None, # 要关联的表中的字段名称on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为- models.CASCADE,删除关联数据,与之关联也删除- models.DO_NOTHING,删除关联数据,引发错误IntegrityError- models.PROTECT,删除关联数据,引发错误ProtectedError- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)- models.SET,删除关联数据,a. 与之关联的值设置为指定值,设置:models.SET(值)b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)def func():return 10class MyModel(models.Model):user = models.ForeignKey(to="User",to_field="id"on_delete=models.SET(func),)related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:# 如:- limit_choices_to={'nid__gt': 5}- limit_choices_to=lambda : {'nid__gt': 5}from django.db.models import Q- limit_choices_to=Q(nid__gt=10)- limit_choices_to=Q(nid=8) | Q(nid__gt=10)- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')db_constraint=True # 是否在数据库中创建外键约束parent_link=False # 在Admin中是否显示关联数据OneToOneField(ForeignKey)to, # 要进行关联的表名to_field=None # 要关联的表中的字段名称on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为###### 对于一对一 ####### 1. 一对一其实就是 一对多 + 唯一索引# 2.当两个类之间有继承关系时,默认会创建一个一对一字段# 如下会在A表中额外增加一个c_ptr_id列且唯一:class C(models.Model):nid = models.AutoField(primary_key=True)part = models.CharField(max_length=12)class A(C):id = models.AutoField(primary_key=True)code = models.CharField(max_length=1)ManyToManyField(RelatedField)to, # 要进行关联的表名related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:# 如:- limit_choices_to={'nid__gt': 5}- limit_choices_to=lambda : {'nid__gt': 5}from django.db.models import Q- limit_choices_to=Q(nid__gt=10)- limit_choices_to=Q(nid=8) | Q(nid__gt=10)- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段# 做如下操作时,不同的symmetrical会有不同的可选字段models.BB.objects.filter(...)# 可选字段有:code, id, m1class BB(models.Model):code = models.CharField(max_length=12)m1 = models.ManyToManyField('self',symmetrical=True)# 可选字段有: bb, code, id, m1class BB(models.Model):code = models.CharField(max_length=12)m1 = models.ManyToManyField('self',symmetrical=False)through=None, # 自定义第三张表时,使用字段用于指定关系表through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表from django.db import modelsclass Person(models.Model):name = models.CharField(max_length=50)class Group(models.Model):name = models.CharField(max_length=128)members = models.ManyToManyField(Person,through='Membership',through_fields=('group', 'person'),)class Membership(models.Model):group = models.ForeignKey(Group, on_delete=models.CASCADE)person = models.ForeignKey(Person, on_delete=models.CASCADE)inviter = models.ForeignKey(Person,on_delete=models.CASCADE,related_name="membership_invites",)invite_reason = models.CharField(max_length=64)db_constraint=True, # 是否在数据库中创建外键约束db_table=None, # 默认创建第三张表时,数据库中表的名称
三、ORM对单表的操作
在setting文件里加入以下代码可以实时显示操作对应的SQL语句
LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console': {'level': 'DEBUG','class': 'logging.StreamHandler',},},'loggers': {'django.db.backends': {'handlers': ['console'],'propagate': True,'level': 'DEBUG',},}
}
1. 增
from app01.models import *#create方式一: Author.objects.create(name='Alvin')#create方式二: Author.objects.create(**{"name":"alex"})#save方式一: author=Author(name="alvin")author.save()#save方式二: author=Author()author.name="alvin"author.save()
# 方式一b = Book(name='python基础', price=99, author='alex', pub_date='2017-12-12')b.save()# 方式二Book.objects.create(name='Linux基础', price=49, author='lsf', pub_date='2015-03-12')
2. 改
# 方式一Book.objects.filter(author='alex').update(price='999') # 不能用get(author='alex')# 方式二b = Book.objects.get(author='lsf')b.price = 120b.save()
注意:
<1>第一种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)。
<2>save方法会将所有属性重新设定一遍,效率低,推荐使用第一种方式
3. 删
Book.objects.filter(author='lsf').delete()
4. 查
# 查询相关API:# <1>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象# <2>all(): 查询所有结果# <3>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------# <4>values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列# <5>exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象# <6>order_by(*field): 对查询结果排序# <7>reverse(): 对查询结果反向排序# <8>distinct(): 从返回结果中剔除重复纪录# <9>values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列# <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。# <11>first(): 返回第一条记录# <12>last(): 返回最后一条记录# <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False。
booklist = Book.objects.filter(author='alex') # 得到一个集合booklist = Book.objects.all()booklist = Book.objects.all()[::2]booklist = Book.objects.all()[::2]booklist = Book.objects.get(name='Go') # 只能取出一条结果时才不报错booklist = Book.objects.first()booklist = Book.objects.last()booklist = Book.objects.exclude(author='alex')print(booklist) # <QuerySet [<Book: Book object (Linux基础)>, <Book: Book object (PHP)>]>booklist = Book.objects.filter(author='alex').reverse() # 倒叙booklist = Book.objects.exclude(author='alex').order_by('price') # 排序print(booklist) # <QuerySet [<Book: Book object (PHP)>, <Book: Book object (Linux基础)>]>ret1 = Book.objects.filter(author='alex').values('name', 'price')print(ret1) # <QuerySet [{'name': 'GO', 'price': 55}, {'name': 'python基础', 'price': 99}]>ret2 = Book.objects.filter(author='alex').values_list('name', 'price')print(ret2) # <QuerySet [('GO', 55), ('python基础', 99)]>booklist = Book.objects.all().values('name').distinct() # 去重book_count = Book.objects.exclude(author='alex').count() # 返回查询结果的数量
模糊查询(双下划线)
# 大于,小于## models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值# models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值# models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值# models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值# in## models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据# models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in# isnull# Entry.objects.filter(pub_date__isnull=True)# contains## models.Tb1.objects.filter(name__contains="ven")# models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感# models.Tb1.objects.exclude(name__icontains="ven")# range## models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and# 其他类似## startswith,istartswith, endswith, iendswith,# order by## models.Tb1.objects.filter(name='seven').order_by('id') # asc# models.Tb1.objects.filter(name='seven').order_by('-id') # desc# group by## from django.db.models import Count, Min, Max, Sum# models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"# limit 、offset## models.Tb1.objects.all()[10:20]# regex正则匹配,iregex 不区分大小写## Entry.objects.get(title__regex=r'^(An?|The) +')# Entry.objects.get(title__iregex=r'^(an?|the) +')# date## Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))# year## Entry.objects.filter(pub_date__year=2005)# Entry.objects.filter(pub_date__year__gte=2005)# month## Entry.objects.filter(pub_date__month=12)# Entry.objects.filter(pub_date__month__gte=6)# day## Entry.objects.filter(pub_date__day=3)# Entry.objects.filter(pub_date__day__gte=3)# week_day## Entry.objects.filter(pub_date__week_day=2)# Entry.objects.filter(pub_date__week_day__gte=2)# hour## Event.objects.filter(timestamp__hour=23)# Event.objects.filter(time__hour=5)# Event.objects.filter(timestamp__hour__gte=12)# minute## Event.objects.filter(timestamp__minute=29)# Event.objects.filter(time__minute=46)# Event.objects.filter(timestamp__minute__gte=29)# second## Event.objects.filter(timestamp__second=31)# Event.objects.filter(time__second=2)# Event.objects.filter(timestamp__second__gte=31)
四、多表操作
如何处理外键关系的字段如一对多的publish和
多对多的authors
1. 一对多
增
# 方式一:由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个字段设定对应值:# Book.objects.create(name='Linux', price=80, pubdate='2017-12-12', publish_id=1) # 相当于绑定了Publish表中id为1的对象# 方式二:先获取要绑定的Publish对象,再绑定给publishpublish_obj = Publish.objects.filter(name='人民出版社')[0]Book.objects.create(name='Linux', price=80, pubdate='2017-12-12', publish=publish_obj)
查(通过对象)
book_obj = Book.objects.get(name='python')print(book_obj.price) # 99# 一对多:book_obj.publish一定是一个对象print(book_obj.publish) # Publish object (3)print(book_obj.publish.name) # 南方出版社# 查询人民出版社的所有书籍# 方法一(正向查找)pub_obj = Publish.objects.get(name='人民出版社')ret = Book.objects.filter(publish=pub_obj).values('name', 'price')print(ret) # <QuerySet [{'name': 'Linux', 'price': 80}, {'name': 'Java', 'price': 150}]># 方法二(反向查找)pub_obj = Publish.objects.get(name='人民出版社')print(pub_obj.book_set.all().values('name', 'price')) # <QuerySet [{'name': 'Linux', 'price': 80}, {'name': 'Java', 'price': 150}]># print(type(pub_obj.book_set.all())) # <class 'django.db.models.query.QuerySet'>
查(通过双下划线)
book_dic = Book.objects.filter(publish__name='人民出版社').values('name', 'price')print(book_dic)# 查找python的出版社名字ret1 = Publish.objects.get(book__name='python').nameret2 = Publish.objects.filter(book__name='python').values('name')ret3 = Book.objects.get(name='python').publish.nameret4 = Book.objects.filter(name='python').values('publish__name')print(ret1, ret2, ret3, ret4)# 查找出版社在北京的书籍ret5 = Publish.objects.filter(addr='北京').values('book__name')ret6 = Book.objects.filter(publish__addr='北京').values('name')print(ret5, ret6)
2. 多对多
增
book_obj = Book.objects.get(id=10)authors_objs = Author.objects.filter(age__lt=40)book_obj.authors.add(*authors_objs)author1=Author.objects.get(id=1)author2=Author.objects.filter(name='alvin')[0]book=Book.objects.get(id=1)book.authors.add(author1,author2)#等同于:book.authors.add(*[author1,author2])book.authors.remove(*[author1,author2])#-------------------book=Book.objects.filter(id__gt=1)authors=Author.objects.filter(id=1)[0]authors.book_set.add(*book)authors.book_set.remove(*book)#-------------------book.authors.add(1)book.authors.remove(1)authors.book_set.add(1)authors.book_set.remove(1)#注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式
# 如果第三张表是自己创建的:class Book2Author(models.Model):author=models.ForeignKey("Author")Book= models.ForeignKey("Book")
# 那么就还有一种方式:author_obj=models.Author.objects.filter(id=2)[0]book_obj =models.Book.objects.filter(id=3)[0]s=models.Book2Author.objects.create(author_id=1,Book_id=2)s.save()s=models.Book2Author(author=author_obj,Book_id=1)s.save()
删
#正向
book = Book.objects.filter(id=1)book.author.clear() #清空与book中id=1 关联的所有数据
book.author.remove(2) #可以为id
book.author.remove(*[1,2,3,4]) #可以为列表,前面加*#反向
author = Author.objects.filter(id=1)
author.book_set.clear() #清空与boy中id=1 关联的所有数据
改
obj=Book.objects.filter(id=1)[0]author=Author.objects.filter(id__gt=2)obj.author.clear()obj.author.add(*author)
查
# 多对多# 查找python的作者Book.objects.filter(name='python').values('authors__name')Author.objects.filter(book__name='python').values('name')# 查找出版社在北京的书籍的名字和作者Book.objects.filter(publish__addr='北京').values('name', 'authors__name')Author.objects.filter(book__publish__addr='北京').values('book__name', 'name')Publish.objects.filter(addr='北京').values('book__name', 'book__authors__name')# 查找作者为alex的书的出版社名字Author.objects.filter(name='alex').values('book__publish__name')Book.objects.filter(authors__name='alex').values('publish__name')Publish.objects.filter(book__authors__name='alex').values('name')
3. 聚合查询和分组查询
<1>aggregate(*args, **kwargs)
通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
from django.db.models import Avg,Min,Sum,Max从整个查询集生成统计值。比如,你想要计算所有在售书的平均价钱。Django的查询语法提供了一种方式描述所有
图书的集合。>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}aggregate()子句的参数描述了我们想要计算的聚合值,在这个例子中,是Book模型中price字段的平均值aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的
标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定
一个名称,可以向聚合子句提供它:
>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
<2>annotate(*args, **kwargs)
可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
查询alex出的书总价格
查询各个作者出的书的总价格,这里就涉及到分组了,分组条件是authors__name
查询各个出版社最便宜的书价是多少
4. F查询和Q查询
仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询:
# F 使用查询条件的值,专门取对象中某列值的操作# from django.db.models import F# models.Tb1.objects.update(num=F('num')+1)# Q 构建搜索条件from django.db.models import Q#1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询q1=models.Book.objects.filter(Q(title__startswith='P')).all()print(q1)#[<Book: Python>, <Book: Perl>]# 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。Q(title__startswith='P') | Q(title__startswith='J')# 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合Q(title__startswith='P') | ~Q(pub_date__year=2005)# 4、应用范围:# Each lookup function that takes keyword-arguments (e.g. filter(),# exclude(), get()) can also be passed one or more Q objects as# positional (not-named) arguments. If you provide multiple Q object# arguments to a lookup function, the arguments will be “AND”ed# together. For example:Book.objects.get(Q(title__startswith='P'),Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))#sql:# SELECT * from polls WHERE question LIKE 'P%'# AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')# import datetime# e=datetime.date(2005,5,6) #2005-05-06# 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。# 正确:Book.objects.get(Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),title__startswith='P')# 错误:Book.objects.get(question__startswith='P',Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
5. 其他操作
def select_related(self, *fields)性能相关:表之间进行join连表操作,一次性获取关联的数据。model.tb.objects.all().select_related()model.tb.objects.all().select_related('外键字段')model.tb.objects.all().select_related('外键字段__外键字段')def prefetch_related(self, *lookups)性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。# 获取所有用户表# 获取用户类型表where id in (用户表中的查到的所有用户ID)models.UserInfo.objects.prefetch_related('外键字段')from django.db.models import Count, Case, When, IntegerFieldArticle.objects.annotate(numviews=Count(Case(When(readership__what_time__lt=treshold, then=1),output_field=CharField(),)))students = Student.objects.all().annotate(num_excused_absences=models.Sum(models.Case(models.When(absence__type='Excused', then=1),default=0,output_field=models.IntegerField())))def distinct(self, *field_names)# 用于distinct去重models.UserInfo.objects.values('nid').distinct()# select distinct nid from userinfo注:只有在PostgreSQL中才能使用distinct进行去重def order_by(self, *field_names)# 用于排序models.UserInfo.objects.all().order_by('-id','age')def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)# 构造额外的查询条件或者映射,如:子查询Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))Entry.objects.extra(where=['headline=%s'], params=['Lennon'])Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])# select id, select id from tb where id > 1 as new_id order by nid descdef reverse(self):# 倒序models.UserInfo.objects.all().order_by('-nid').reverse()# 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序def defer(self, *fields):models.UserInfo.objects.defer('username','id')或models.UserInfo.objects.filter(...).defer('username','id')#映射中排除某列数据def only(self, *fields):#仅取某个表中的数据models.UserInfo.objects.only('username','id')或models.UserInfo.objects.filter(...).only('username','id')# 与values的区别:# 使用only得到的列表里封装的是对象 [obj{id,name},obj,obj],使用obj.age依然可以拿到值,但会重新发起一次sql请求# values得到的列表是字典 [{id, name},{id,name}]def using(self, alias):指定使用的数据库,参数为别名(setting中的设置)#
def raw(self, raw_query, params=None, translations=None, using=None):# 执行原生SQLmodels.UserInfo.objects.raw('select * from userinfo')# 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名models.UserInfo.objects.raw('select id as nid from 其他表')# 为原生SQL设置参数models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])# 将获取的到列名转换为指定列名name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)# 指定数据库models.UserInfo.objects.raw('select * from userinfo', using="default")################### 原生SQL ###################from django.db import connection, connectionscursor = connection.cursor() # cursor = connections['default'].cursor()cursor.execute("""SELECT * from auth_user where id = %s""", [1])row = cursor.fetchone() # fetchall()/fetchmany(..)
def none(self):# 空QuerySet对象def dates(self, field_name, kind, order='ASC'):# 根据时间进行某一部分进行去重查找并截取指定内容# kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)# order只能是:"ASC" "DESC"# 并获取转换后的时间- year : 年-01-01- month: 年-月-01- day : 年-月-日models.DatePlus.objects.dates('ctime','day','DESC')def datetimes(self, field_name, kind, order='ASC', tzinfo=None):# 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间# kind只能是 "year", "month", "day", "hour", "minute", "second"# order只能是:"ASC" "DESC"# tzinfo时区对象models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))"""pip3 install pytzimport pytzpytz.all_timezonespytz.timezone(‘Asia/Shanghai’)"""
def bulk_create(self, objs, batch_size=None):# 批量插入# batch_size表示一次插入的个数objs = [models.DDD(name='r11'),models.DDD(name='r22')]models.DDD.objects.bulk_create(objs, 10)def get_or_create(self, defaults=None, **kwargs):# 如果存在,则获取,否则,创建# defaults 指定创建时,其他字段的值obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})def update_or_create(self, defaults=None, **kwargs):# 如果存在,则更新,否则,创建# defaults 指定创建时或更新时的其他字段obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})def in_bulk(self, id_list=None):# 根据主键ID进行查找id_list = [11,21,31]models.DDD.objects.in_bulk(id_list)
转载于:https://www.cnblogs.com/lsf123456/p/11376251.html
Django-07-Model操作相关推荐
- Django之Model操作
Django之Model操作 本节内容 字段 字段参数 元信息 多表关系及参数 ORM操作 1. 字段 字段列表 AutoField(Field)- int自增列,必须填入参数 primary_key ...
- Python之路【第二十二篇】:Django之Model操作
Django之Model操作 一.字段 AutoField(Field)- int自增列,必须填入参数 primary_key=TrueBigAutoField(AutoField)- bigint自 ...
- python Django Session,CSRF,Model操作,Form验证,中间件,缓存,信号
Django Session,CSRF,Model操作,Form验证,中间件,缓存,信号 Session CSRF Model 操作 Form 验证 中间件 缓存 信号 1,Session 基于coo ...
- Django的model查询操作 与 查询性能优化
Django的model查询操作 与 查询性能优化 1 如何 在做ORM查询时 查看SQl的执行情况 (1) 最底层的 django.db.connection 在 django shell 中使用 ...
- Django中model新建数据表操作后admin页面不更新问题
Django中model新建数据表操作后admin页面不更新问题 这种情况一般是没有在admin.py文件中进行模型的注册所导致的,打开应用文件夹下的admin.py,然后添加代码: from .mo ...
- Django中Model模块的操作-创建各种表结构(上)
Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLd ...
- 西游之路——python全栈——Django之ORM操作
Django之ORM操作 前言 Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计 ...
- django中model模型
python manage.py dumpdata blog # 导出blog数据 python manage.py loaddata blog_dump.json # 导入数据 m ...
- Django中Model继承的三种方式
Django中Model继承的三种方式 Django中Model的继承有三种: 1.抽象继承 2.多表继承 3.proxy model(代理model) 1.抽象继承 第一种抽象继承,创建一个通用父类 ...
- 【Django】ORM操作#2
目录 必知必会的13条查询方法 单表查询之神奇的双下划线 一对多 ForeignKey 多对多 ManyToManyField 在Python脚本中调用Django环境 Django终端打印SQL语句 ...
最新文章
- python连接oracle批量写入_oracle大数据量python导入实践-1w/s
- 100. Same Tree同样的树
- Json序列化提示缺少编译器要求的成员“ystem.Runtime.CompilerServices.ExtensionAttribute..ctor”...
- linux上yum最简方法安装,yum轻松简单安装配置GCC等
- AX2009 的EP开发要点
- 详解Java动态代理机制
- linux网关管理,利用Linux打造安全的管理型网关
- SQL Server修改表结构时,不允许保存更改,阻止保存要求重新创建表的更改
- AD快捷键,及一些基本操作设置总结
- 英语报纸计算机类,报纸和电脑英语作文
- 广电行业编码传输系统调研
- H5纯页面方式手机端实现“扫一扫”功能(不是直接调起摄像头)
- win7锁定计算机自动关机,windows7怎么设置电脑自动关机_win7如何自动关机
- ndis协议驱动开发
- Web项目经理手册之项目经理需要铭记在心的话
- 分布式系统的CAP原理及其应用
- ERDAS 9.2安装教程
- 定时器输出PWM原理
- [论文]自主水下机器人垂直面路径跟踪静态输出反馈控制设计
- Python 结合Ansible 把管理资产信息自动插入到CMDB中