django——models
ORM简介(说白了就是不用自己写sql语句,只需要操作ORM这个模块,让这个模块帮我们去执行sql语句) ? MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库 ? ORM是“对象-关系-映射”的简称,主要任务是: 1、根据对象的类型生成表结构 2、将对象、列表的操作,转换为sql语句 3、将sql查询到的结果转换为对象、列表 ? ? 好处: 这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动 Django中的模型包含存储数据的字段和约束,对应着数据库中唯一的表 ? ? ? ? ? ? ? 拿mysql数据库来举例: ? ? ? 1、在虚拟环境中安装mysql包 pip install pymysql ???===>在python2中对应的是mysql-python这个包 ? ? ? 2、先手工在mysql创建一个新的数据库 create database test charset=utf8 ? ? ? 3、打开settings.py文件,修改DATABASES项 DATABASES = { ????‘default‘: { ????????‘ENGINE‘: ‘django.db.backends.mysql‘, ????????‘NAME‘: ‘test‘,?# 数据库名 ????????‘USER‘: ‘用户名‘, ????????‘PASSWORD‘: ‘密码‘, ????????‘HOST‘: ‘数据库服务器ip,本地可以使用localhost‘, ????????‘PORT‘: ‘端口,默认为3306‘, ????} } ? ? ? 4、创建一个应用 python manage.py startapp booktest2 问题:此时创建应用时会报错:django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named ‘MySQLdb‘ 解决方式:在项目同名目录下(项目目录)的init.py中加入如下代码即可: import pymysql pymysql.install_as_MySQLdb() ? ? 4.1定义模型 1、定义一个类就是定义了一张表(表名默认为:应用名_类名)。定义一个类属性就是在这张表里定义一个列名,定义类属性(列)的时候可以规定这个类属性的一些类型信息,这些类型信息决定了如下内容: ? 当前类属性(列名)的基本属性(是数字还是时间还是字符串?如果是字符串的话长度又为多少?等等属性信息。。。) ? 根据定义的类属性基本情况,会在admin管理页面渲染成不同的显示效果(控件)。例:如果类属性为时间的话就会渲染成一个日历,如果类型属性为bool类型的话可能会渲染成一个可以打钩的小方框 ? 提供一些基本的验证功能。比如:定义的类属性为一个bool类型,你输入一个字符串时就会告诉你输入的类型不对 ? 2、django会为表添加自动增长的主键列,每个模型只能有一个主键列,如果使用手工设置某属性为主键列后,则django不会再生成默认的主键列 ? 3、类属性命名时的一些限制: ? 1、不能是python的保留关键字 ? 2、不能使用连续的下划线(原因是两个下划线是django中的一个查询标识符) ? ? 4.1.1定义模型中类的属性 ? ????1、字段类型 ? ????????字段类型概念:这个‘类属性/列名‘是一个什么类型(字符串?数字?时间?)。 字段类型被定义在django.db.models.fields这个文件内。 ? ????????字段类型使用方式: ?????????????1、导入from django.db import models ?????????????2、通过models.Field创建字段类型对象,赋值给类属性 ? ????????提醒:在对重要数据做删除时一定要做逻辑删除,不能做物理删除。实现方法是定义idDelete类属性,类型为BooleanField,默认值为False。 ? ? ? ????????常用字段类型说明: ????????AutoField:一个根据实际ID自动增长的IntegerField,通常不指定,如果不指定,一个主键字段将自动添加到模型中 ????????BooleanField:true/false 字段,此字段的默认表单控制是CheckboxInput ????????NullBooleanField:支持null、true、false三种值 ????????CharField(max_length=字符长度):字符串,默认的表单样式是 TextInput ????????TextField:大文本字段,一般超过4000使用,默认的表单控件是Textarea ????????IntegerField:整数 ????????????DecimalField(max_digits=None,decimal_places=None):使用python的Decimal实例表示的十进制浮点数 ????????????DecimalField.max_digits:位数总数 ????????DecimalField.decimal_places:小数点后的数字位数 ????????FloatField:用Python的float实例来表示的浮点数 ????????DateField[auto_now=False,auto_now_add=False]):使用Python的datetime.date实例表示的日期 ????????????参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false ????????????参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false ????????????该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键 ????????????auto_now_add,auto_now,and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果 ????????TimeField:使用Python的datetime.time实例表示的时间,参数同DateField ????????DateTimeField:使用Python的datetime.datetime实例表示的日期和时间,参数同DateField ????????FileField:一个上传文件的字段 ????????ImageField:继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image ? ? ? ????????字段选项(定义字段时括号里加的参数)说明: ? ????????作用:通过字段选项,可以实现对字段的约束 ? ????????null:如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False ????????blank:如果为True,则该字段允许为空白,默认值是 False ?===>null和blank的区别:null是如果表单不填则以null代替,blank规定了这个表单是否是必填项 ????????db_column:字段的名称,如果未指定,则使用属性的名称 ????????db_index:若值为 True,则在表中会为此字段创建索引 ????????default:默认值 ????????primary_key:若为 True,则该字段会成为模型的主键字段 ????????unique:如果为 True,这个字段在表中必须有唯一值 ? ? ? ????2、关系说明: ? ????????关系的类型包括: ????????????ForeignKey:一对多,将字段定义在多的端中 ??===>比如一本书里有5个英雄,那就在5个英雄身上分别填上一个属性来标明它是哪本书上的英雄 ????????????ManyToManyField:多对多,将字段定义在两端中 ????????????OneToOneField:一对一,将字段定义在任意一端中 ? ????????那么怎样通过关系来查找数据呢? ? ????????例:有两张表:bookinfo、heroinfo ????????class BookInfo(models.Model): ????????????pass ????????class HeroInfo(models.Model): ????????????book=models.ForeignKey(BookInfo) ????????现在有一英雄对象hero,想要看这个英雄属于哪本书可以直接hero.book ????????现在有一本书的对象book,但是关系又维护在HerInfo这个表中,此时怎样看这本书上都有哪些英雄呢?此时可以使用这种方法:book.heroinfo_set ? ? ? ????3、元选项说明: ? ????????修改元选项的作用: ????????1、修改数据库表的名称(如果不修改则默认表名为“应用名_类名”) ????????2、修改数据库内数据的排序方式(默认按ID从小到大排序,注意:排序会增加数据库的开销) ? ????????修改元选项方法: ????????在模型类中定义类Meta。例: ????????class BookInfo(models.Model): ????????????... ????????????class Meta(): ????????????????ordering = [‘id‘] ??===>基于“id”排序。注:字符串前加-表示倒序,不加-表示正序 ???????? db_table = ‘bookinfo‘ ?===>修改表名为“bookinfo” ? ? ? ????4、管理器Manager (管理器只有作为模型类的一个属性时才能和模型类形成绑定关系,如果管理器不和模型类绑定则无意义,以后对这个类模型/表进行操作都由管理器来完成): ????????作用:对数据库进行增删改查 ? ????????在查询数据时用到的object是Manager类型的对象,用于和数据库进行交互 ????????当定义模型类时没有指定管理器,则Django会为模型类提供一个名为objects的默认管理器 ????????当为模型类指定管理器后,django不再为模型类生成名为objects的默认管理器,例: ????????class BookInfo(models.Model): ????????????... ????????????books = models.Manager() ? ? ????????objects是ORM模块的核心(即默认的管理器),管理器是Django模型进行数据库查询操作的接口,Django应用的每个模型都拥有至少一个管理器。 ? ????????如果你觉得django自带的object不好用可以自己重写一个。如果要重写管理器的话一般有两个目的: ? ????????1、向管理器类中添加额外的方法:创建一个新的类(管理器)来继承models.Manager,然后在这个类里添加自己定义的方法 ? ????????2、改变默认查询结果(即将查询到的结果经过自定义处理后再输出):重写getqueryset()方法即可 ???????? ????????class BookInfoManager(models.Manager): ????????????# 改变默认查询结果(只查询isDelete=False的数据) ????????????def get_queryset(self): ????????????????return super(BookInfoManager,self).get_queryset().filter(isDelete=False) ? ????????????# 定义自定义方法 ????????????def xxx(self): ????????????????pass ? ????????# 定义一个模型类,在这个模型类里使用我们重写过的管理器 ????????class BookInfo(mldels.Model): ????????????... ????????????# 一个模型类里可以定义多个管理器 ????????????books = models.Manager() ????????????books2 = BookInfoManager() ??# 自定义的那个管理器 ? ????5、创建模型类对象(创建数据,一个对象就是一条数据) ????????当创建对象时,django不会对数据库进行读写操作 ????????调用save()方法才与数据库交互,将对象保存到数据库中 ????????_init _方法已经在基类models.Model中使用,在自定义模型中无法使用,所以推荐使用下面的两种之一: ? ????????方式一(创建一个类方法): ?????????class BookInfo(models.Model): ????????????... ????????????@classmethod ????????????def create(cls,title,pub_date): ????????????????book = cls(btitle=title,bpub_date=pub_date) ????????????????book.bread=0 ????????????????book.bcommet=0 ????????????????book.isDelete = False ????????????????return book ? ????????引入时间包:from datetime import * ????????调用:book=BookInfo.create("hello",datetime(1980,10,11)); ????????保存:book.save() ? ????????方式二(在自定义管理器中添加一个方法。 ??-----django官方推荐 ): ????????class BookInfoManager(models.Manager): ????????????def create_book(self,pub_date): ????????????????book = self.model() # 在管理器的方法中,可以通过self.model来得到它所属的模型类 ????????????????book.btitle = title ????????????????book.bpub_date = pub_date ????????????????book.bread=0 ????????????????book.bcommet=0 ????????????????book.isDelete = False ????????????????return book ? ????????class BookInfo(models.Model): ????????????... ????????????books = BookInfoManager() ? ????????引入时间包:from datetime import * ????????调用:book=BookInfo.books.create_book("abc",1,1)) ????????保存:book.save() ? ????????方式二优化写法(推荐!): 在方式二中,可以调用self.create()创建并保存对象,不需要再手动save() ????????class BookInfoManager(models.Manager): ????????????def create_book(self,pub_date): ????????????????book = self.create(btitle = title,bpub_date = pub_date,bread=0,bcommet=0,isDelete = False) ????????????????return book ? ????????class BookInfo(models.Model): ????????????... ????????????books = BookInfoManager() ????????调用:book=Book.books.create_book("abc",1)) ????????查看:book.pk ?# 查看这本书里有多少条数据 ? ? 5、查询 ???? ????5.1背景: ????????1、查询集表示从数据库中获取的对象集合 ????????2、查询集可以含有零个、一个或多个过滤器 ????????3、过滤器基于所给的参数限制查询的结果 ????????4、从Sql的角度,查询集和select语句等价,过滤器像where和limit子句 ? ????5.2查询集: ????????在管理器上调用过滤器方法会返回查询集 ????????查询集经过过滤器筛选后返回新的查询集,因此可以写成链式过滤 ????????返回查询集的方法,称为过滤器 ????????惰性执行:创建查询机不会带来任何数据库的访问,直到调用数据时(什么时候算调用呢? 迭代,序列化,与if合用等情况算调用),才会访问数据库。例: ????????????a = abc.objects.all() ?# 此时并不和数据库交互(我就纳闷了,这里不和数据库进行交互他是怎么知道数据库里一共有几条数据的) ????????????for i in a: ????# 此时因为迭代里面的数据才会和数据库进行交互 ????????????????print(i) ? ? ????5.3过滤器自带的几种查询方法: ? ????????一、返回全部数据 ????????all() ?===>显示全部的对象 ????????filter() ?===>显示经过过滤后剩下的对象 ????????exclude() ?===>和filter相反 ????????order_by() ??===>排序输出 ????????values() ??===>将查询到的每个对象实际指向的数据形成一个字典,然后若干字典构成一个列表返回 ? ????????filter()参数写法(and关系): ????????????filter(键1=值1,键2=值2) ????????????等价于 ????????????filter(键1=值1).filter(键2=值2) ? ? ????????二、返回单个数据 ????????get() ????????????如果未找到会引发"模型类.DoesNotExist"异常 ????????????如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常 ????????count() ?===>返回数据个数统计 ????????first() ?===>返回第一个数据对象 ????????last() ?===>返回最后一个数据对象 ????????exists() ?===>判断是否有满足条件的数据,如果有则返回True ? ? ????5.4、限制查询集 ????????查询集返回列表,可以使用下标的方式进行限制(注意:不支持负数索引),等同于sql中的limit和offset子句 ????????使用下标后返回一个新的查询集,不会立即执行查询(惰性执行) ????????如果获取一个对象,直接使用[0],等同于[0:1].get(),但是如果没有数据,[0]引发IndexError异常,[0:1].get()引发DoesNotExist异常 ? ? ????5.5、查询集的缓存 ????????每个查询集都包含一个缓存来最小化对数据库的访问 ????????在新建的查询集中,缓存为空,首次对查询集求值时,会发生数据库查询,django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存的结果 ???????? ????????情况一:这构成了两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载 ????????????print([e.title for e in Entry.objects.all()]) ????????????print([e.title for e in Entry.objects.all()]) ????????情况二:两次循环使用同一个查询集,第二次使用缓存中的数据 ????????????querylist=Entry.objects.all() ????????????print([e.title for e in querylist]) ????????????print([e.title for e in querylist]) ? ????????有一种情况是不会缓存的: ????????query=BookInfo.objects.all() ????????for i in query[0:10]: ?# 第一次迭代的时候会将[0:10]这部分缓存 ????????????print(i) ????????for i in query[11:20]: ?# 第二次迭代如果迭代的是部分数据则先看这部分数据在缓存内是否有数据,如果没有则从数据库拉过数据来之后也不会再次缓存 ????????????print(i) ? ? ????5.6、字段查询 ? ????????背景: ????????1、查询条件作为查询方法filter()、exclude()、get()的参数 ????????2、语法:类模型.管理器.all().查询方法(类属性名称__比较运算符=值)。 例:BookInfo.books1.all().filter(btitle__=‘天龙八部‘) ??(注意:这里是两个下划线) ????????3、对于外键,使用“类属性名_id”表示外键的原始值 ? ????????5.6.1、过滤条件 ????????????比较运算符(在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith) ? ????????????exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等 ????????????filter(isDelete=False) ???和 ???filter(isDelete__exact=False) ???的效果是一样的 ? ????????????contains:是否包含,大小写敏感 ????????????filter(btitle__contains=‘传‘) ? ????????????startswith、endswith:以value开头或结尾,大小写敏感 ????????????filter(btitle__startswith=‘笑‘) ????????????filter(btitle__endswith=‘传‘) ? ????????????isnull、isnotnull:是否为null ????????????filter(btitle__isnull=False) ? ????????????in:是否包含在范围内 ????????????filter(pk__in=[1,2,3,4,5]) ? ????????????gt、gte、lt、lte:大于、大于等于、小于、小于等于 ????????????filter(id__gt=3) ? ????????????year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算 ????????????filter(bpub_date__year=1980) ????????????filter(bpub_date__gt=date(1980,12,31)) ? ? ????????5.6.2、跨关联关系的查询 ????????????语法:模型类名 <属性名> <比较> ????????????注:可以没有__<比较>部分,表示等于,结果同inner join ????????????可返向使用,即在关联的两个模型中都可以使用,例: ????????????????class BookInfo(models.Model): ????????????????????btitle = models.CharField(max_length=20) ????????????????????bpub_date = models.DateTimeField() ????????????????????bread = models.IntegerField(default=0) ????????????????????bcommet = models.IntegerField(default=0) ????????????????????isDelete = models.BooleanField(default=False) ????????????????????books1 = BookInfoManager() ? ????????????????class HeroInfo(models.Model): ????????????????????hname = models.CharField(max_length=20) ????????????????????hgender = models.BooleanField(default=True) ????????????????????isDelete = models.BooleanField(default=False) ????????????????????hcontent = models.CharField(max_length=100) ????????????????????hbook = models.ForeignKey(‘BookInfo‘) ? ????????????BookInfo.books1.all().filter(heroinfo_ _hconten=‘八‘) ?# 查询BookInfo表中,所含英雄的hconten字段有等于‘八‘的书 ????????????BookInfo.books1.all().filter(heroinfo_ _hcontent_ _contains=‘八‘) ?# 查询BookInfo表中,所含英雄的hconten字段有包含‘八‘的书 ????????????HeroInfo.objects.all().filter(hbook__btitle=‘天龙八部‘) ?# 查询所有属于‘天龙八部‘这本书上的英雄 ? ????????????思考:我怎么从BookInfo这张表上查询指定书上的所有英雄呢? ????????????答:暂时认为不能从书的表上查英雄。 暂时总结为:书的表就只能查书,英雄的表就只能查英雄 ????????????答:又回顾了下,好像可以用BookInfo.heroinfo_set来查询指定书上的所有英雄 ? ? ????????????彩蛋====>依据主键来查询的快捷方式: ????????????pk:pk表示primary key,默认的主键是id ????????????filter(pk__lt=6) ? ? ????????5.6.3、聚合函数 ????????????使用aggregate()函数返回聚合函数的值 ????????????函数:Avg,Count,Max,Min,Sum ? ????????????用Max来举例: ????????????????from django.db.models import Max ?????????????????BookInfo.books1.aggregate(Max(‘bread‘)) ? ? ????????5.6.4、F对象 ????????????之前的比较运算都是用类模型的一个字段与一个常量进行比较,用F对象可以实现用类模型中的两个字段做比较。例: ????????????????from django.db.models import F ????????????????BookInfo.books1.filter(bread__gte=F(‘bcommet‘)) ???# bread>=bcommet的数据都列出来 ? ????????????????django支持对F()对象使用算数运算 ????????????????BookInfo.books1.filter(bread__gte=F(‘bcommet‘)*2) ? ????????????????F()对象中还可以写作“模型类__列名”进行关联查询 ????????????????BookInfo.books1.filter(isDelete=F(‘heroinfo__isDelete‘)) ? ????????????????对于date/time字段,可与timedelta()进行运算 ????????????????BookInfo.books1.filter(bpub_date__lt=F(‘bpub_date‘) + timedelta(days=1)) ? ? ????????5.6.5、Q对象(用于处理逻辑or运算) ? ????????????逻辑过滤方式(and、or): ? ????????????and关系: ????????????????filter()参数写法(and关系): ????????????????filter(键1=值1,键2=值2) ????????????????等价于 ????????????????filter(键1=值1).filter(键2=值2) ? ????????????or关系: ????????????????from django.db.models import Q ????????????????BookInfo.books1.filter(Q(bread__gte=50) | Q(bcommet__gte=50)) ?# 查询bread>=50或bcommet>=50的书 ? ????????????使用~(not)操作符在Q对象前表示取反 ????????????????BookInfo.books1.filter(~Q(pk__lt=6)) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |