Django 數據庫高級操做-過濾,反向查詢,性能

前面豆子已經陸陸續續地學習了在Django中如何操做數據庫 html


單表的基本操做 http://beanxyz.blog.51cto.com/5570417/1945887 python

常見字段的使用 http://beanxyz.blog.51cto.com/5570417/1945909 數據庫

最基本的查詢方式 http://beanxyz.blog.51cto.com/5570417/1950806 django

一對多的基本操做和實例  http://beanxyz.blog.51cto.com/5570417/1946602 編程

多對多的基本操做和實例 http://beanxyz.blog.51cto.com/5570417/1952243 app


下面補充一些高級操做。
ide


條件的過濾 函數

下面是常見的條件設置,除了能夠基本的filter以外,咱們還有大量的條件語句可使用。 性能


查詢數據庫獲取的QuerySet類型,對於這個類型咱們相似Jquery同樣使用鏈式編程,能夠無限制的經過.來添加新的條件來過濾,能夠看見大部分條件都是經過雙下劃線__來實現的 學習


# 獲取個數
        # 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等於十一、2二、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)


上面這些方法能夠實現大部分常見的簡單查詢過濾。有的時候,咱們須要實現一些更復雜的查詢語句,上面的語句就不夠用了,這個時候能夠經過extra來擴展。例如,主要看看select和where的自定義


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



反向查詢


以前的博文裏面,咱們都是經過正向查找外鍵或者中間表來獲取另一個表的信息;若是但願倒過來,也是經過雙下劃線,好比 表名__字段 這種形式來實現



實例:

3張表,分別是單表,1對多和多對多的關係

#業務線
class Business(models.Model):
    # id
    caption = models.CharField(max_length=32)
#主機
class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field='id')
#程序
class Application(models.Model):
    name = models.CharField(max_length=32,unique=True)
    r = models.ManyToManyField("Host")

視圖函數

def tt(request):
    #1對多正向查找
    print('1對多正向查找'.center(40, '-'))
    obj=models.Host.objects.filter(nid__gt=1)
    print(obj[0].nid,obj[0].hostname,obj[0].b.caption)
    #一些過濾條件
    print('過濾條件'.center(40,'-'))
    obj=models.Business.objects.filter(caption__contains='SALE').first()
    print(obj.id,obj.caption)
    obj=models.Business.objects.all().values('id','caption')
    print(obj, obj.order_by('id').reverse())
    obj=models.Application.objects.filter(name__exact='SQL Server').values('name','r__hostname','r__nid')
    print(obj)
    #1對多反向查找
    print('1對多反向查找'.center(40,'-'))
    obj=models.Business.objects.all().values('id','caption','host__ip','host__hostname')
    print(obj[0])
    #多對多正向查找
    print('多對多正向查找'.center(40, '-'))
    obj=models.Application.objects.all().first()
    print(obj.name, obj.r.all()[0].hostname)
    #多對多反向查詢
    print('多對多反向查找'.center(40, '-'))
    obj=models.Host.objects.all().filter(nid__gt=1).values('nid','application__name').first()
    print(obj)
    return HttpResponse('ok')



執行結果

----------------1對多正向查找-----------------
183 SYDMGM01 SALE
------------------過濾條件------------------
5 SALE
<QuerySet [{'id': 5, 'caption': 'SALE'}, {'id': 19, 'caption': 'IT'}, {'id': 20, 'caption': 'HR'}]> <QuerySet [{'id': 20, 'caption': 'HR'}, {'id': 19, 'caption': 'IT'}, {'id': 5, 'caption': 'SALE'}]>
<QuerySet [{'name': 'SQL Server', 'r__hostname': 'SYDMGM01', 'r__nid': 183}, {'name': 'SQL Server', 'r__hostname': 'SYDAV01', 'r__nid': 190}, {'name': 'SQL Server', 'r__hostname': 'SYDMGM02', 'r__nid': 191}]>
----------------1對多反向查找-----------------
{'id': 5, 'caption': 'SALE', 'host__ip': '10.2.1.1', 'host__hostname': 'SYDMGM01'}
----------------多對多正向查找-----------------
AA SYDMGM01
----------------多對多反向查找-----------------
{'nid': 183, 'application__name': 'AA'}



性能


假設咱們有一個Use表經過外鍵ut綁定了一個UserType表


默認狀況下,若是咱們直接使用下面代碼,若是uses獲取了10行數據,那麼數據庫實際上查詢11次,對user查詢一次,而後在for循環裏面對usertype查詢10次;這樣效率很低

users = models.User.objects.all()
for row in users:
    print(row.user,row.pwd,row.ut_id)
    print(row.ut.name)


咱們能夠經過select_related進行優化,這樣第一次查詢的時候就進行一個跨表查詢,獲取指定外鍵的全部數據

users = models.User.objects.all().select_related('ut')
for row in users:
    print(row.user,row.pwd,row.ut_id)
    print(row.ut.name)


若是數據比較多,外鍵也多,那麼速度可能還會比較慢,比較跨表查詢的效率比較低,那麼進一步的咱們能夠經過prefetch_related優化。他的基本原理是進行屢次單表查詢;好比第一次查詢User表,而後第二次查詢外鍵關聯的表,而後把全部數據都放在內存裏面,這樣訪問的速度就會快不少了。

users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu')
# select * from users where id > 30
# 獲取上一步驟中全部的ut_id=[1,2]
# select * from user_type where id in [1,2]
# select * from user_type where id in [1,2]
for row in users:
    print(row.user,row.pwd,row.ut_id)
    print(row.ut.name)



參考資料:http://www.cnblogs.com/wupeiqi/articles/5246483.html

相關文章
相關標籤/搜索