1.orm简介

对象关系映射(Object Relational Mapping, 简称ORM)
简言之,ORM是通过使用描述对象和数据库之间映射的源数据,将程序中的对象自动持久化到关系数据库中.

ORM的优点:

  1. 不用写繁琐的SQL代码,使用熟悉的python代码就能实现对数据的操作,提高开发效率;
  2. 可以平滑的操作,切换数据库;

ORM的缺点:

  1. ORM代码转换为SQL语句时,需要花费一定的时间,执行效率会有所降低;
  2. 长期写ORM代码,可能会导致SQL语句能力有所降低;

2. ORM中常用字段介绍

每个字段中有一些特有的参数,例如Charfield需要max_length参数来指定VARCHAR数据库字段的大小.还有一些适用于所有字段的通用参数.以下介绍一些常用的字段

"""
<1> Charfield字符串字段,用于较短的字符串.Charfield 要求必须有一个参数 maxlength,用于从数据库层和Django校验层限制该字段所允许的最大字符数.<2> IntegerField用于保存整数.<3> FloatField一个浮点数.  必须提供两个参数max_digits  总位数(不包括小数点和符号)decimal_places  小数位数举例来说,如果要保存一个最大值为999,且小数点后保存两位的浮点数,需要这样定义字段:models.FloatField(..., max_digits=5, decimal_places=2)<4> AutoField一个 IntegerField,添加记录时他会自动增长, 你通常不需要直接使用这个字段;自定义一个主键: my_id = models.AutoField(primary_key=True)如果你不定义主键的话,系统会主动添加一个主键字段到你的model.<5> BooleanFieldA true/false field. admin 用checkbox 来表示此类字段<6> TextField一个容量很大的文本字段admin 用一个<textarea>(文本区域)表示该字段数据. (一个多行编辑框)<7> EmailField一个带有检查Email合法性的CharFiled,不接受 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> 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参数.

3. ORM的增删改查

3.1 添加表记录
  1. 方式一: 通过类实例化对象,注意一定要 对象.save()
book = models.Book(title="吸星大法", price=200, publisher="明教出版社", pub_date="2018-12-12")
book.save()
  1. 方式二: 通过ORM提供的 objects 提供的方法 create 来实现.
book = models.Book.objects.create(title="独孤九剑", price=150, publisher="华山出版社", pub_date="2019-1-12")
3.2 查询表记录
  1. 查询API
"""
<1> all() :   查询所有结果<2> fillter(**kwargs) : 包含与所给筛选条件<3> get(**kwargs):   返回所给筛选条件相匹配的对象,返回结果有且只有一个.如果没有符合条件的则报错.<4> exclude(**kwargs): 包含与所给筛选条件不匹配的对象<5> order_by(*field):  对查询结果排序<6> reverse(): 对查询结果反向排序<7> count(): 返回数据库中匹配查询(QuerySet)的对象数量<8> first():     返回第一条记录<9> last():        返回最后一条记录<10> exists():    如果QuerySet包含数据,就返回True, 否则返回False<11> value(*field):  返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列.<12> value_list(*field):      它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列.<13> distinct():        从返回结果中剔除重复记录
  1. 基于双下划线的查询
Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100)
Book.objects.filter(price__lt=100)
Book.objects.filter(price__range=[100,200])
Book.objects.filter(title__contains="法")
Book.objects.filter(title__icontains="python")  # 不区分大小写
Book.objects.filter(title__startswith="九")
Book.objects.filter(pub_date__year=2018)
3.3 删除表记录

删除的方法就是delete(). 他运行时立即删除对象而不返回任何值.例如:

model_obj.delete()

也可以一次性删除多个对象.每个QuerySet都有一个delete()方法,它一次性删除QuerySet中所有的对象.例如:

Book.objects.filter(pub_date_year=2018).delete()

在Django删除对象时,会模仿SQL 约束 ON DELETE CASCADE的行为,换句话说,删除一个对象时他也会删除与他相关联的外连接对象.

b = Book.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

要注意的是: delete() 方法是 QuerySet 上的方法,但并不适用于 Manage本身.这是一种保护机制,是为了避免意外地调用Entry.objects.delete() 方法导致 所有的记录被误删除.如果你确认要删除所有的对象,那么你必须显示地调用:

Book.objects.all().delete()

all() 是manager方法

3.4 修改表记录
  1. 通过修改实例对象的属性方式. 注意: 一定要对象.save()
book = models.Book.objects.get(title="吸星大法")
book.price = 100
book.save()

2.通过ORM提供的objects提供的方法 update来实现.

models.Book.objects.filter(title="吸星大法").update(price=100)

此外,update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

4. QuerySet详解(拓展内容,转载)

概述:
Django ORM用到三个类:Manager、QuerySet、Model。Manager定义表级方法(表级方法就是影响一条或多条记录的方法),我们可以以models.Manager为父类,定义自己的manager,增加表级方法;QuerySet:Manager类的一些方法会返回QuerySet实例,QuerySet是一个可遍历结构,包含一个或多个元素,每个元素都是一个Model 实例,它里面的方法也是表级方法,前面说了,Django给我们提供了增加表级方法的途径,那就是自定义manager类,而不是自定义QuerySet类,一般的我们没有自定义QuerySet类的必要;django.db.models模块中的Model类,我们定义表的model时,就是继承它,它的功能很强大,通过自定义model的instance可以获取外键实体等,它的方法都是记录级方法(都是实例方法,貌似无类方法),不要在里面定义类方法,比如计算记录的总数,查看所有记录,这些应该放在自定义的manager类中.

4.1 QuerySet简介

每个Model都有一个默认的manager实例,名为objects,QuerySet有两种来源:通过manager的方法得到、通过QuerySet的方法得到。mananger的方法和QuerySet的方法大部分同名,同意思,如filter(),update()等,但也有些不同,如manager有create()、get_or_create(),而QuerySet有delete()等,看源码就可以很容易的清楚Manager类与Queryset类的关系,Manager类的绝大部分方法是基于Queryset的。一个QuerySet包含一个或多个model instance。QuerySet类似于Python中的list,list的一些方法QuerySet也有,比如切片,遍历。

>>> from userex.models import UserEx
>>> type(UserEx.objects)
<class ‘django.db.models.manager.Manager’>>>> a = UserEx.objects.all()
>>> type(a)
<class ‘django.db.models.query.QuerySet’>

QuerySet是延迟获取的,只有当用到这个QuerySet时,才会查询数据库求值另外,查询到的QuerySet又是缓存的,当再次使用同一个QuerySet时,并不会再查询数据库,而是直接从缓存获取(不过,有一些特殊情况)。一般而言,当对一个没有求值的QuerySet进行运算,返回的是QuerySet、ValuesQuerySet、ValuesListQuerySet、Model实例时,一般不会立即查询数据库;反之,当返回的不是这些类型时,会查询数据库。 下面介绍几种(并非全部)对QuerySet求值的场景。

class Blog(models.Model):name = models.CharField(max_length=100)tagline = models.TextField()def __unicode__(self):return self.nameclass Author(models.Model):name = models.CharField(max_length=50)email = models.EmailField()def __unicode__(self):return self.nameclass Entry(models.Model):blog = models.ForeignKey(Blog)headline = models.CharField(max_length=255)body_text = models.TextField()pub_date = models.DateField()mod_date = models.DateField()authors = models.ManyToManyField(Author)n_comments = models.IntegerField()n_pingbacks = models.IntegerField()rating = models.IntegerField()def __unicode__(self):return self.headlin

我们就以上面的models为例。

1.遍历
a = Entry.objects.all()
for e in a:print (e.headline)

当遍历一开始时,先从数据库执行查询select * from Entry得到a,然后再遍历a。注意:这里只是查询Entry表,返回的a的每条记录只包含Entry表的字段值,不管Entry的model中是否有onetoone、onetomany、manytomany字段,都不会关联查询。这遵循的是数据库最少读写原则。我们修改一下代码,如下,遍历一开始也是先执行查询得到a,但当执行print (e.blog.name)时,还需要再次查询数据库获取blog实体。

from django.db import connectionl = connection.queries  #l是一个列表,记录SQL语句
a = Entry.objects.all()for e in a:print (e.blog.name)print(len(l))

遍历时,每次都要查询数据库,l长度每次增1,Django提供了方法可以在查询时返回关联表实体,如果是onetoone或onetomany,那用select_related,不过对于onetomany,只能在主表(定义onetomany关系的那个表)的manager中使用select_related方法,即通过select_related获取的关联对象是model instance,而不能是QuerySet,如下,e.blog就是model instance。对于onetomany的反向和manytomany,要用prefetch_related,它返回的是多条关联记录,是QuerySet。

a = Entry.objects.select_related('blog')
for e in a:print (e.blog.name)print(len(l))

可以看到从开始到结束,l的长度只增加1。另外,通过查询connection.queries[-1]可以看到Sql语句用了join。所以使用select_related来获取查找关联对象,速度会更快。

2.切片

切片不会立即执行,除非显示指定了步长,如a= Entry.objects.all()[0:10:2],步长为2。

3.序列化,即Pickling

序列化QuerySet很少用,这里不讨论,读者可以自行查找资料。

4.repr()

和str()功能相似,将对象转为字符串,很少用。

5.len()

计算QuerySet元素的数量,并不推荐使用len(),除非QuerySet是求过值的(即evaluated),否则,用QuerySet.count()获取元素数量,这个效率要高。

6.list()

将QuerySet转为list

7.bool(),判断是否为空
if Entry.objects.filter(headline="Test"):print("There is at least one Entry with the headline Test")

同样不建议这种方法判断是否为空,而应该使用QuerySet.exists(),查询效率高。

4.2 QuerySet的方法(*******)

数据库的常用操作就四种:增、删、改、查,QuerySet的方法涉及删、改、查。后面还会讲model对象的方法,model方法主要是增、删、改、还有调用model实例的字段。

1.delete():删

原型:delete()
返回:None
相当于sql语句的delete-from-where, delete-from-join-where。先filter,然后对得到的QuerySet执行delete()方法就行了,它会同时删除关联它的那些记录,比如我删除记录表1中的A记录,表2中的B记录中有A的外键,那同时也会删除B记录,那ManyToMany关系呢?对于ManyToMany,删除其中一方的记录时,会同时删除中间表的记录,即删除双方的关联关系。由于有些数据库,如Sqlite不支持delete与limit连用,所以在这些数据库对QuerySet的切片执行delete()会出错。如

>>> a = UserEx.objects.filter(is_active=False)>>> b = a[:3]>>> b.delete() #执行时会报错

解决:UserEx.objects.filter(pk__in=b).delete() ,in后面可以是一个QuerySet。

2.update():改

批量修改,返回修改的记录数。不过update()中的键值对的键只能是主表中的字段,不能是关联表字段,如下
最好的方法是先filter,查询出QuerySet,然后再执行QuerySet.update()。

Entry.objects.update(blog__name='foo')  #错误,无法修改关联表字段,只能修改Entry表的字段Entry.objects.filter(blog__name='foo').update(comments_on=False)  #正确
3.filter(**kwargs)、exclude(**kwargs)、get(**kwargs):查询

相当于select-from-where,select-from-join-where,很多网站读数据库操作最多。可以看到,filter()的参数是变个数的键值对,而不会出现>,<,!=等符号,这些符号分别用__gt,__lt,~Q或exclude(),不过对于!=,建议使用Q查询,更不容易出错。可以使用双下划线对OneToOne、OneToMany、ManyToMany进行关联查询和反向关联查询,而且方法都是一样的,如:

>>> Entry.objects.filter(blog__name='Beatles Blog') #限定外键表的字段

下面是反向连接,不过要注意,这里不是entry_set,entry_set是Blog instance的一个属性,代表某个Blog object的关联的所有entry,而QuerySet的方法中反向连接是直接用model的小写,不要把两者搞混。

>>> Blog.objects.filter(entry__headline__contains='Lennon')>>> Blog.objects.filter(entry__authors__name='Lennon')   #ManyToMany关系,反向连接>>> myblog = Blog.objects.get(id=1)>>> Entry.objects.filter(blog=myblog) #正向连接。既可以用实体,也可以用实体的主键,其实即使用实体,也是只用实体的主键而已。这两种方式对OneToOne、OneToMany、ManyToMany的正向、反向连接都适用。>>> Entry.objects.filter(blog=1)    #我个人不建议这样用,对于create(),不支持这种用法>>> myentry = Entry.objects.get(id=1)>>> Blog.objects.filter(entry=myentry) #ManyToMany反向连接。与下面两种方法等价>>> Blog.objects.filter(entry=1)   >>> Blog.objects.filter(entry_id=1)  #适用于OneToOne和OneToMany的正向连接

OneToOne的关系也是这样关联查询,可以看到,Django对OneToOne、OneToMany、ManyToMany关联查询及其反向关联查询提供了相同的方式,真是牛逼啊。对于OneToOne、OneToMany的主表,也可以使用下面的方式:
Entry.objects.filter(blog_id=1),因为blog_id是数据库表Entry的一个字段, 这条语句与Entry.objects.filter(blog=blog1)生成的SQL是完全相同的。
与filter类似的还有exclude(**kwargs)方法,这个方法是剔除,相当于sql语句的select-from-where not。可以使用双下划线对OneToOne、OneToMany、ManyToMany进行关联查询和反向关联查询,方法与filter()中的使用方法相同。

>>> Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

转为SQL为:

SELECT *FROM EntryWHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
4.SQL其它关键字在django中的实现

在SQL中,很多关键词在删、改、查时都是可以用的,如order by、 like、in、join、union、and、or、not等等,我们以查询为例,说一下django如何映射SQL的这些关键字的(查、删、改中这些关键字的使用方法基本相同)。

1.F类(无对应SQL关键字)
前面提到的filter/exclude中的查询参数值都是常量,如果我们想比较model的两个字段怎么办呢?Django也提供了方法,F类,F类实例化时,参数也可以用双下划线,也可以逻辑运算,如下:

>>> from django.db.models import F>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))>>> from datetime import timedelta>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))>>> Entry.objects.filter(authors__name=F('blog__name'))

2.Q类(对应and/or/not)
如果有or等逻辑关系呢,那就用Q类,filter中的条件可以是Q对象与非Q查询混和使用,但不建议这样做,因为混和查询时Q对象要放前面,这样就有难免忘记顺序而出错,所以如果使用Q对象,那就全部用Q对象。Q对象也很简单,就是把原来filter中的各个条件分别放在一个Q()即可,不过我们还可以使用或与非,分别对应符号为”|”和”&”和”~”,而且这些逻辑操作返回的还是一个Q对象,另外,逗号是各组条件的基本连接符,也是与的关系,其实可以用&代替(在python manage.py shell测试过,&代替逗号,执行的SQL是一样的),不过那样的话可读性会很差,这与我们直接写SQL时,各组条件and时用换行一样,逻辑清晰。

from django.db.models import Q>>> Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),question__startswith='Who')   #正确,但不要这样混用>>> Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),Q(question__startswith='Who'))  #推荐,全部是Q对象>>> Poll.objects.get( (Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))&Q(question__startswith='Who'))  #与上面语句同意,&代替”,”,可读性差Q类中时应该可以用F类,待测试。

3.annotate(无对应SQL关键字)
函数原型annotate(*args, **kwargs)、
返回QuerySet
往每个QuerySet的model instance中加入一个或多个字段,字段值只能是聚合函数,因为使用annotate时,会用group by,所以只能用聚合函数。聚合函数可以像filter那样关联表,即在聚合函数中,Django对OneToOne、OneToMany、ManyToMany关联查询及其反向关联提供了相同的方式,见下面例子。

#计算每个用户的userjob数量,字段命名为ut_num,返回的QuerySet中的每个object都有
#这个字段。在UserJob中定义User为外键,在Job中定义与User是ManyToMany
>>> from django.contrib.auth.models import User
>>> from django.db.models import Count>>>> a = User.objects.filter(is_active=True, userjob__is_active=True). annotate(n=Count(‘userjob’)) #一对多反向连接
>>> b = User.objects.filter(is_active=True, job__is_active=True).annotate(n=Count(‘job__name’))  #多对多反向连接,User与Job是多对多
>>> len(a)  #这里才会对a求值
>>> len(b)  #这里才会对b求值

a对应的SQL语句为(SQL中没有为表起别名,u、ut是我加的):

select auth.user.*,Count(ut.id) as ut_num
from auth_user as u
left outer join job_userjob as ut on u.id = ut.user_id
where u.is_active=True and ut.is_active=True
group by u.*

4.order_by——对应order by
函数原型 order_by(*fields)
返回QuerySet
正向的反向关联表跟filter的方式一样。如果直接用字段名,那就是升序asc排列;如果字段名前加-,就是降序desc。

Entry.objects.all().order_by("pub_date ")

5.distinct——对应distinct
原型 distinct()
一般与values()、values_list()连用,这时它返回ValuesQuerySet、ValuesListQuerySet
这个类跟列表很相似,它的每个元素是一个字典。它没有参数(其实是有参数的,不过,参数只在PostgreSQL上起作用)。使用方法为:

>>> a=Author.objects.values_list(name).distinct()
>>> b=Author.objects.values_list(name,email).distinct()

对应的sql语句分别为:

select distinct name
from Author
和
seect distinct name,email
from Author

6.values()和values_list()——对应‘select 某几个字段’
函数原型values(*field), values_list(*field)
返回ValuesQuerySet, ValuesListQuerySet

Author.objects.filter(**kwargs)对应的SQL只返回主表(即Author表)的所有字段值,即使在查询时关联了其它表,关联表的字段也不会返回,只有当我们通过Author instance用关联表时,Django才会再次查询数据库获取值。当我们不用Author instance的方法,且只想返回几个字段时,就要用values(),它返回的是一个ValuesQuerySet对象,它类似于一个列表,不过,它的每个元素是字典。而values_list()跟values()相似,它返回的是一个ValuesListQuerySet,也类型于一个列表,不过它的元素不是字典,而是元组。一般的,当我们不需要model instance的方法且返回多个字段时,用values(*field),而返回单个字段时用values_list(‘field’,flat=True),这里flat=True是要求每个元素不是元组,而是单个值,见下面例子。而且我们可以返回关联表的字段,用法跟filter中关联表的方式完全相同。

>>> a = User.objects.values(‘id’,’username’,’userex__age’)
>>> type(a)
<class ‘django.db.models.query.ValuesQuerySet’>
>>> a
[{‘id’:0,’username’:u’test0’,’ userex__age’: 20},{‘id’:1,’username’:u’test1’,’userex__age’: 25},{‘id’:2,’username’:u’test2’, ’ userex__age’: 28}]
>>> b= User.objects.values_list(’username’,flat=True)
>>> b
[u’test0’, u’test1’ ,u’test2’]

7.select_related()——对应返回关联记录实体
原型select_related(*filed)
返回QuerySet

它可以指定返回哪些关联表model instance,这里的field跟filter()中的键一样,可以用双下划线,但也有不同,QuerySet中的元素中的OneToOne关联及外键对应的是都是关联表的一条记录,如my_entry=Entry.objects.get(id=1),my_entry.blog就是关联表的一条记录的对象。select_related()不能用于OneToMany的反向连接,和ManyToMany,这些都是model的一条记录对应关联表中的多条记录。前面提到了对于a = Author.objects.filter(**kwargs)这类语句,对应的SQL只返回主表,即Author的所有字段,并不会返回关联表字段值,只有当我们使用关联表时才会再查数据库返回,但有些时候这样做并不好。看下面两段代码,这两段代码在1.1中提到过。在代码1中,在遍历a前,先执行a对应的SQL,拿到数据后,然后再遍历a,而遍历过程中,每次都还要查询数据库获取关联表。代码2中,当遍历开始前,先拿到Entry的QuerySet,并且也拿到这个QuerySet的每个object中的blog对象,这样遍历过程中,就不用再查询数据库了,这样就减少了数据库读次数。

a = Entry.objects.all()
for e in a:print (e.blog.name)
################
a = Entry.objects.select_related('blog')
for e in a:print (e.blog.name)

8.prefetch_related(*field) ——对应返回关联记录实体的集合
函数原型prefetch_related(*field)
返回的是QuerySet

这里的field跟filter()中的键一样,可以用双下划线。用于OneToMany的反向连接,及ManyToMany。其实,prefetch_related()也能做select_related()的事情,但由于策略不同,可能相比select_related()要低效一些,所以建议还是各管各擅长的。select_related是用select ……join来返回关联的表字段,而prefetch_related是用多条SQL语句的形式查询,一般,后一条语句用IN来调用上一句话返回的结果。

class Restaurant(models.Model):pizzas = models.ManyToMany(Pizza, related_name='restaurants')best_pizza = models.ForeignKey(Pizza, related_name='championed_by')>>> Restaurant.objects.prefetch_related('pizzas__toppings')
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')

先用select_related查到best_pizza对象,再用prefetch_related 从best_pizza查出toppings

9.extra()——实现复杂的where子句
具体可以看这篇文章:https://www.cnblogs.com/gaoya666/p/8877116.html

  1. aggregate(*args, kwargs)——对应聚合函数
    参数为聚合函数,最好用
    kwargs的形式,每个参数起一个名字。
    该函数与annotate()有何区别呢?annotate相当于aggregate()和group by的结合,对每个group执行aggregate()函数。而单独的aggregate()并没有group by。
>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))  #这是用*args的形式,最好不要这样用
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))  #这是用**kwargs的形式
{'number_of_entries': 16}

至此,我们总结了QuerySet方法返回的数据形式,主要有五种。第一种:返回QuerySet,每个object只包含主表字段;第二种:返回QuerySet,每个object除了包含主表所有字段,还包含某些关联表的object,这种情况要用select_related()和prefetch_related(),可以是任意深度(即任意多个双下划线)的关联,通常一层关联和二层关联用的比较多;第三种:返回ValuesQuerySet, ValuesListQuerySet,它们的每个元素包含若干主表和关联表的字段,不包含任何实体和关联实例,这种情况要用values()和values_list();第四种:返回model instance;第五种:单个值,如aggregate()方法。

11.exists()、count()、len()
如果只是想知道一个QuerySet是否为空,而不想获取QuerySet中的每个元素,那就用exists(),它要比len()、count()、和直接进行if判断效率高。如果只想知道一个QuerySet有多大,而不想获取QuerySet中的每个元素,那就用count();如果已经从数据库获取到了QuerySet,那就用len()。

12.contains/startswith/endswith——对应like
字段名加双下划线,除了它,还有icontains,即Case-insensitive contains,这个是大小写不敏感的,这需要相应数据库的支持。有些数据库需要设置才能支持大小写敏感。

  1. in——对应in
    使用:字段名加双下划线

14.exclude(field__in=iterable)——对应not in
iterable是可迭代对象

15.gt/gte/lt/lte——对应于>,>=,<,<=
字段名加双下划线

16.range——对应于between and
字段名加双下划线,range后面值是列表

17.isnull——对应于is null
Entry.objects.filter(pub_date__isnull=True)对应的SQL为SELECT … WHERE pub_date IS NULL;

  1. QuerySet切片——对应于limit
    QuerySet的索引只能是非负整数,不支持负整数,所以QuerySet[-1]错误
a=Entry.objects.all()[5:10]
b=len(a)

执行Entry.objects.all()[5:8],对于不同的数据库,SQL语句不同,Sqlite 的SQL语句为select * from tablename limit 3 offset 5; MySQL的SQL语句为select * from tablename limit 5,3

原文链接:https://www.cnblogs.com/ajianbeyourself/p/3604332.html#_label1

Django 之ORM(一)相关推荐

  1. django mysql orm教程_带你了解Django ORM操作(基础篇)

    前言 在日常开发中,需要大量对数据库进行增删改查操作. 如果头铁的话,使用原生SQL是最好的,毕竟性能又高,又灵活. 但是通常情况下,我们不是太需要那么苛刻的性能,也没有那么多刁钻的需求用原生SQL ...

  2. Django 数据库ORM 操作 - 字段的类型和参数

    通过Django的ORM创建表的时候,我们需要定义自己的类. 定义类的时候,他有各种各样的字段类型,每个字段都有自己的参数可以进行配置,下面简单的归纳一下. 首先看看字段的类型.尽管Python提供了 ...

  3. Django 中ORM 的使用

    一:Django 中 orm 的使用 1:手动新建一个数据库 2 :告诉Django连接哪个数据库 settings.py里配置数据库连接信息: #数据库相关的配置项 DATABASES ={'def ...

  4. Django基础——ORM字段和字段参数

    ORM概念: 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象( 1. 不同的程序员写的SQL水平参差不齐 2. ...

  5. 【Django】ORM操作#2

    目录 必知必会的13条查询方法 单表查询之神奇的双下划线 一对多 ForeignKey 多对多 ManyToManyField 在Python脚本中调用Django环境 Django终端打印SQL语句 ...

  6. django -- 实现ORM登录

    前戏 上篇文章写了一个简单的登录页面,那我们可不可以实现一个简单的登录功能呢?如果登录成功,给返回一个页面,失败给出错误的提示呢? 在之前学HTML的时候,我们知道,网页在往服务器提交数据的时候,都是 ...

  7. django orm插入一条_如何通过django的ORM远程发布文章?

    利用django的ORM可以方便的给数据库插入文章 但是假如我django放在阿里云,那我想在本地写个插件,每天很方便的插入一些数据,最好是通过ORM的,因为管理起来比较方便,会涉及到多个站,可能会有 ...

  8. django 模板mysql_59 Django基础三件套 , 模板{{}}语言 , 程序连mysql Django项目app Django中ORM的使用...

    主要内容:https://www.cnblogs.com/liwenzhou/p/8688919.html 1 form表单中提交数据的三要素 a : form标签必须要有action和method的 ...

  9. django的orm指定字段名,表名 verbose_name_plural

    django的orm指定字段名,表名 verbose_name_plural 1.指定字段名: 在定义字段的时候,增加参数db_column='real_field': 2.指定表名: 在model的 ...

  10. django orm_Django ORM简介

    django orm 您可能听说过Django ,它是Python Web框架,用于"有期限的完美主义者". 就是那个可爱的小马 . Django最强大的功能之一是其对象关系映射器 ...

最新文章

  1. r语言 编辑 d3.js_d3.js的语言介绍
  2. index match函数的使用方法_必学函数组合INDEX+MATCH,秒杀VLOOKUP函数
  3. 关于bhuman文件结构
  4. 【CV】使用OpenCV进行消失点检测(附代码)
  5. 在gitlab 中使用webhook 实现php 自动部署git 代码
  6. Triangle Counting【数学】
  7. Bootstrap 列平移/列偏移
  8. 实现根据条件删除_强大的定位空值法,1秒删除所有不想要的数据
  9. 群聊太多?三步教你用 Python 自动监听转发群消息
  10. 递归的Fibonacci在数羊
  11. java__斐波那契数列
  12. cad插件加载bplot成功用不了_教大家Batchplot使用常见问题的解决办法
  13. 开源开放 | OpenKG发布第二批并更新近十个新冠知识图谱开放数据集
  14. 计算机计算涨跌的公式,计算股票涨跌的神器—四段五点模型计算器
  15. material-table的使用
  16. vue(slot-卡槽)
  17. PBC Library Manual(PBC库手册)翻译(一)
  18. 键盘触发keypress事件,键值列表
  19. 【Matlab】极点配置控制(PPC)
  20. ae表达式修复_AE脚本-AE模板表达式错误修复脚本WINMAC

热门文章

  1. Python——星期的字典1——7
  2. 号脉数据中心全生命周期,业务永续从细节做起
  3. matlab设计走马灯,移动端UI样式-走马灯
  4. MPLS多协议标签交换技术
  5. java 调用打印机
  6. 2021谷歌算法排名因素大全
  7. 个人支付宝/微信/云闪付收款技术总览
  8. 遭遇职场官斗,外派回来岗位被占!
  9. 计算机基础知识(二)
  10. pycharm 【Debug】过程卡住不动