ORM

ORM基本操作

Object Relational Mapping

Posted by youyue on January 31, 2018

一.单表操作

基本操作

from app01.models import * 增:

Tb1.objects.create(c1='xx', c2='oo')   # 增加一条数据,可以接受字典类型数据 **kwargs

obj = models.Tb1(c1='xx', c2='oo')
obj.save()

删:

Tb1.objects.filter(name='seven').delete()  # 删除指定条件的数据

改:

models.Tb1.objects.filter(name='seven').update(gender='0')   # 将指定条件的数据更新,均支持 **kwargs

obj = models.Tb1.objects.get(id=1)
obj.c1 = '111'
obj.save()   # 修改单条数据

查:

Tb1.objects.get(id=123)  # 获取单条数据,不存在则报错(不建议)
Tb1.objects.all()  		 # 获取全部
Tb1.objects.filter(name='seven')   # 获取指定条件的数据
Tb1.objects.exclude(name='seven')  # 去除指定条件的数据

进阶操作

	# 获取个数
	#
	# models.Tb1.objects.filter(name='seven').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)

F和Q查询

	# extra
    #
    # 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'])

    # F
    #
    # from django.db.models import F
    # models.Tb1.objects.update(num=F('num')+1)


    # Q
    #
    # 方式一:
    # Q(nid__gt=10)
    # Q(nid=8) | Q(nid__gt=10)
    # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
    # 方式二:
    # con = Q()
    # q1 = Q()
    # q1.connector = 'OR'
    # q1.children.append(('id', 1))
    # q1.children.append(('id', 10))
    # q1.children.append(('id', 9))
    # q2 = Q()
    # q2.connector = 'OR'
    # q2.children.append(('c1', 1))
    # q2.children.append(('c1', 10))
    # q2.children.append(('c1', 9))
    # con.add(q1, 'AND')
    # con.add(q2, 'AND')
    #
    # models.Tb1.objects.filter(con)


    # 执行原生SQL
    #
    # from django.db import connection, connections
    # cursor = connection.cursor()  # cursor = connections['default'].cursor()
    # cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    # row = cursor.fetchone()

常用API

# 查询相关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

注意:其中get/first/last返回的是obj, count返回的是次数,exists返回布尔值,其余都是Queryset

二.多表查询

表结构

# 书
class Book(models.Model):
    title = models.CharField(max_length=32)
    publish_date = models.DateField(auto_now_add=True)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 创建外键,关联publish
    publisher = models.ForeignKey(to="Publisher")
    # 创建多对多关联author
    author = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title


# 出版社
class Publisher(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)

    def __str__(self):
        return self.name


# 作者
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    phone = models.IntegerField()
    detail = models.OneToOneField(to="AuthorDetail")

    def __str__(self):
        return self.name


# 作者详情
class AuthorDetail(models.Model):
    addr = models.CharField(max_length=64)
    email = models.EmailField()

单表查询:

查询书名为番茄物语的书
>>> models.Book.objects.filter(title="番茄物语")

一对多查询:

查询id为1的书的出版社所在的城市

>>> models.Book.objects.get(id=1).publisher.city
'北京'
查询id为1的出版社的出版的所有书籍(反向查找)

>>> models.Publisher.objects.get(id=1).book_set.all()
<QuerySet [<Book: 番茄物语>, <Book: 香蕉物语>]>

一对一查询:

查询小精灵作者的邮箱

>>> models.Author.objects.get(name="小精灵").detail.email
'1@1.com'
查询所有addr="快乐星球"的作者姓名

>>> author_details = models.AuthorDetail.objects.filter(addr="快乐星球")
>>> for obj in author_details:
...     print(obj.author.name)
小仙女
小魔女

多对多查询:

>>> models.Book.objects.get(title="番茄物语").author.all()
<QuerySet [<Author: 小精灵>, <Author: 小仙女>]>
>>> for obj in author_list:
...     print(obj.name, obj.detail.email)
... 
小精灵 1@1.com
小仙女 2@2.com

查询小仙女出版的所有书籍

>>> models.Author.objects.get(name="小仙女").book_set.all()
<QuerySet [<Book: 番茄物语>, <Book: 橘子物语>]>

了不起的双下划线

查询沙河出版社出版的所有书籍的名称和价格

(正向查)

>>> models.Book.objects.filter(publisher__name="沙河出版社").values_list("title", "price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>
反向查

>>> models.Publisher.objects.get(name="沙河出版社").book_set.all().values_list("title", "price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>
双下划线反查

>>> models.Publisher.objects.filter(name="沙河出版社").values_list("book__title", "book__price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>

查询小仙女出版的所有书籍名称

正向查

>>> models.Book.objects.filter(author__name="小仙女").values_list("title")
<QuerySet [('番茄物语',), ('橘子物语',)]>
反向查

>>> models.Author.objects.get(name="小仙女").book_set.all().values_list("title")
<QuerySet [('番茄物语',), ('橘子物语',)]>
双下划线反查

>>> models.Author.objects.filter(name="小仙女").values_list("book__title")
<QuerySet [('番茄物语',), ('橘子物语',)]>

查询沙河出版社出版的书籍的书名和作者姓名

正向查

>>> models.Book.objects.filter(publisher__name="沙河出版社").values_list("title", "author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>
反向查

>>> models.Publisher.objects.filter(name="沙河出版社").values_list("book__title", "book__author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>
双下划线反向查

>>> models.Publisher.objects.get(name="沙河出版社").book_set.all().values_list("title", "author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>
查询memo为空的所有书

>>> models.Book.objects.filter(memo__isnull=True)

三.分组查询和聚合查询

aggregate(*args,**kwargs) 聚合函数

  from django.db.models import Avg,Sum,Max,Min
    #求书籍的平均价
    ret=models.Book.objects.all().aggregate(Avg('price'))
    #{'price__avg': 145.23076923076923}

    #参与西游记著作的作者中最老的一位作者
    ret=models.Book.objects.filter(title__icontains='西游记').values('author__age').aggregate(Max('author__age'))
    #{'author__age__max': 518}

    #查看根哥出过得书中价格最贵一本
    ret=models.Author.objects.filter(name__contains='根').values('book__price').aggregate(Max('book__price'))
    #{'book__price__max': Decimal('234.000')}

annotate(*args,**kwargs) 分组函数

	#查看每一位作者出过的书中最贵的一本(按作者名分组 values() 然后annotate 分别取每人出过的书价格最高的)
    ret=models.Book.objects.values('author__name').annotate(Max('price'))
    # < QuerySet[
    # {'author__name': '吴承恩', 'price__max': Decimal('234.000')},
    # {'author__name': '吕不韦','price__max': Decimal('234.000')},
    # {'author__name': '姜子牙', 'price__max': Decimal('123.000')},
    # {'author__name': '亚微',price__max': Decimal('123.000')},
    # {'author__name': '伯夷 ', 'price__max': Decimal('2010.000')},
    # {'author__name': '叔齐','price__max': Decimal('200.000')},
    # {'author__name': '陈涛', 'price__max': Decimal('234.000')},
    # {'author__name': '高路川', price__max': Decimal('234.000')}
    # ] >

    #查看每本书的作者中最老的    按作者姓名分组 分别求出每组中年龄最大的
    ret=models.Book.objects.values('author__name').annotate(Max('author__age'))
    # < QuerySet[
    #  {'author__name': '吴承恩', 'author__age__max': 518},
    #  {'author__name': '张X', 'author__age__max': 18},
    #  { 'author__name': '张X杰', 'author__age__max': 56},
    #  {'author__name': '方X伟', 'author__age__max': 26},
    #  {'author__name': '游X兵', 'author__age__max': 35},
    #  {'author__name': '金庸', 'author__age__max': 89},
    #  { 'author__name': 'X涛', 'author__age__max': 27},
    #  {'author__name': '高XX', 'author__age__max': 26}
    # ] >

    #查看 每个出版社 出版的最便宜的一本书
    ret=models.Book.objects.values('publish__name').annotate(Min('price'))
    # < QuerySet[
    # {'publish__name': '北大出版社','price__min': Decimal('67.000')},
    # {'publish__name': '山西出版社','price__min': Decimal('34.000')},
    # {'publish__name': '河北出版社', 'price__min': Decimal('123.000')},
    # {'publish__name': '浙江出版社', 'price__min': Decimal('2.000')},
    # {'publish__name': '湖北出版社', 'price__min': Decimal('124.000')},
    # {'publish__name': '湖南出版社',price__min': Decimal('15.000')}
    # ] >