ORM常用字段及方式


創建小型數據庫

 

模型層

 

  •      ORM常用字段

AutoField

int自增列,必須填入參數 primary_key=True。當model中如果沒有自增列,則自動會創建一個列名為id的列。

IntegerField

一個整數類型,范圍在 -2147483648 to 2147483647。(一般不用它來存手機號(位數也不夠),直接用字符串存,)

CharField

字符類型,必須提供max_length參數, max_length表示字符長度。

DateField

日期字段,日期格式  YYYY-MM-DD,相當於Python中的datetime.date()實例。

DateTimeField

日期時間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當於Python中的datetime.datetime()實例。

1 class User(models.Model):
2     name = models.CharField(max_length=32)
3     age = models.IntegerField()
4     register_time = models.DateField()
View Code
  1. 字段的參數

null

用於表示某個字段可以為空。

unique

如果設置為unique=True 則該字段在此表中必須是唯一的 。

db_index

如果db_index=True 則代表着為此字段設置索引。

default

為該字段設置默認值。

  2.DateField和DateTimeField

auto_now_add

配置auto_now_add=True,創建數據記錄的時候會把當前時間添加到數據庫。

auto_now

配置上auto_now=True,每次更新數據記錄的時候會更新該字段。

 

  •  關系字段

ForeignKey

 

 

外鍵類型在ORM中用來表示外鍵關聯關系,一般把ForeignKey字段設置在 '一對多'中'多'的一方。

ForeignKey可以和其他表做關聯關系同時也可以和自身做關聯關系。

字段參數

to

設置要關聯的表

to_field

設置要關聯的表的字段

on_delete

當刪除關聯表中的數據時,當前表與其關聯的行的行為。

models.CASCADE

刪除關聯數據,與之關聯也刪除

db_constraint

是否在數據庫中創建外鍵約束,默認為True。

  •   OneToOneField

一對一字段。

通常一對一字段用來擴展已有字段。(通俗的說就是一個人的所有信息不是放在一張表里面的,簡單的信息一張表,隱私的信息另一張表,之間通過一對一外鍵關聯)

字段參數

to

設置要關聯的表。

to_field

設置要關聯的字段。

on_delete

當刪除關聯表中的數據時,當前表與其關聯的行的行為。(參考下面的例子)

1 ef func():
2     return 10
3 
4 class MyModel(models.Model):
5     user = models.ForeignKey(
6         to="User",
7         to_field="id"8         on_delete=models.SET(func)
9     )
 1 返回QuerySet對象的方法有
 2 all()
 3 
 4 filter()
 5 
 6 exclude()
 7 
 8 order_by()
 9 
10 reverse()
11 
12 distinct()
13 
14 特殊的QuerySet
15 values()       返回一個可迭代的字典序列
16 
17 values_list() 返回一個可迭代的元祖序列
18 
19 返回具體對象的
20 get()
21 
22 first()
23 
24 last()
25 
26 返回布爾值的方法有:
27 exists()
28 
29 返回數字的方法有
30 count()
操作小總結

單表查詢操作演示表

 

1 # 單表查詢表
2 class User(models.Model):
3     name = models.CharField(max_length=32)
4     age = models.IntegerField()
5     register_time = models.DateField()
6 
7     def __str__(self):
8         return '對象的名字:%s'%self.name

 

  1  # 新增數據
  2     # 基於create創建
  3     # user_obj = models.User.objects.create(name='tank',age=73,register_time='2019-2-14')
  4     # print(user_obj.register_time)
  5     # 基於對象的綁定方法創建
  6     # user_obj = models.User(name='kevin',age=30,register_time='2019-1-1')
  7     # user_obj.save()
  8     # from datetime import datetime
  9     # ctime = datetime.now()
 10     # models.User.objects.create(name='egon', age=18, register_time=ctime)
 11 
 12 
 13     # 修改數據
 14     # 基於對象
 15     # user_obj = models.User.objects.filter(name='jason').first()
 16     # user_obj.age = 17
 17     # user_obj.save()
 18     # 基於queryset
 19     # models.User.objects.filter(name='kevin').update(age=66)
 20 
 21 
 22     # 刪除數據
 23     # 基於queryset
 24     # models.User.objects.filter(name='egon').delete()
 25     # 基於對象
 26     # user_obj = models.User.objects.filter(name='owen').first()
 27     # user_obj.delete()
 28 
 29 
 30     # 查詢數據
 31     # < 1 > all(): 查詢所有結果
 32 
 33     # < 2 > filter(**kwargs): 它包含了與所給篩選條件相匹配的對象
 34     # res = models.User.objects.filter(name='jason',age=17)
 35     # filter內可以放多個限制條件但是需要注意的是多個條件之間是and關系
 36     # print(res)
 37 
 38     # < 3 > get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。(源碼就去摟一眼~詮釋為何只能是一個對象)
 39     # 不推薦使用
 40 
 41     # < 4 > exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象
 42     # res = models.User.objects.exclude(name='jason')
 43     # print(res)
 44     # < 5 > order_by(*field): 對查詢結果排序('-id') / ('price')
 45     # res = models.User.objects.order_by('age')   # 默認是升序
 46     # res = models.User.objects.order_by('-age')  # 可以在排序的字段前面加一個減號就是降序
 47     # res = models.User.objects.order_by('name')
 48     # res = models.User.objects.order_by('-name')
 49     # print(res)
 50 
 51     # < 6 > reverse(): 對查詢結果反向排序 >> > 前面要先有排序才能反向
 52     # res = models.User.objects.order_by('age').reverse()
 53     # print(res)
 54 
 55     # < 7 > count(): 返回數據庫中匹配查詢(QuerySet) 的對象數量。
 56     # res = models.User.objects.count()
 57     # res = models.User.objects.all().count()
 58     # print(res)
 59 
 60     # < 8 > first(): 返回第一條記錄
 61     # res = models.User.objects.all().first()
 62     # res = models.User.objects.all()[0]  # 不支持負數的索引取值
 63     # print(res)
 64 
 65     # < 9 > last(): 返回最后一條記錄
 66     # res = models.User.objects.all().last()
 67     # print(res)
 68 
 69     # < 10 > exists(): 如果QuerySet包含數據,就返回True,否則返回False
 70     # res = models.User.objects.all().exists()
 71     # res1 = models.User.objects.filter(name='jason',age=3).exists()
 72     # print(res,res1)
 73 
 74     # < 11 > values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行后得到的並不是一系列
 75     # model的實例化對象,而是一個可迭代的字典序列
 76     # res = models.User.objects.values('name')  # 列表套字典
 77     # res = models.User.objects.values('name','age')  # 列表套字典
 78     # print(res)
 79 
 80     # < 12 > values_list(*field): 它與values()
 81     # 非常相似,它返回的是一個元組序列,values返回的是一個字典序列
 82     # res = models.User.objects.values_list('name','age')  # 列表套元祖
 83     # print(res)
 84 
 85     # < 13 > distinct(): 從返回結果中剔除重復紀錄  去重的對象必須是完全相同的數據才能去重
 86     # res = models.User.objects.values('name','age').distinct()
 87     # print(res)
 88 
 89 
 90     # 神奇的雙下划線查詢
 91 
 92     # 查詢年輕大於44歲的用戶
 93     # res = models.User.objects.filter(age__gt=44)
 94     # print(res)
 95     # 查詢年輕小於44歲的用戶
 96     # res = models.User.objects.filter(age__lt=44)
 97     # print(res)
 98     # 查詢年輕大於等於44歲的用戶
 99     # res = models.User.objects.filter(age__gte=44)
100     # print(res)
101     # 查詢年輕小於等於44歲的用戶
102     # res = models.User.objects.filter(age__lte=44)
103     # print(res)
104 
105     # 查詢年齡是44或者22或者73的用戶
106     # res = models.User.objects.filter(age__in=[44,22,73])
107     # print(res)
108 
109     # 查詢年齡在22到44范圍內
110     # res = models.User.objects.filter(age__range=[22,44])
111     # print(res)
112 
113 
114     # 用的是mysql數據庫
115     # 查詢年份
116     # res = models.Book.objects.filter(publish_date__year=2019)
117     # print(res)
118 
119 
120     # 查詢名字中包含字母n的用戶  sqlite數據庫演示不出來大小寫的情況!!!
121     # res = models.Author.objects.filter(name__contains='n')
122     # res = models.Author.objects.filter(name__icontains='n')
123     # print(res)
124     # res = models.User.objects.filter(name__icontains='e')  # 無視大小寫
125     # print(res)
126 
127     # 查詢名字以j開頭的用戶
128     # res = models.User.objects.filter(name__startswith='j')
129     # print(res)
130     # 查詢名字以n結尾的用戶
131     # res = models.User.objects.filter(name__endswith='n')
132     # print(res)
133 
134     # 查詢注冊是在2017年的用戶
135     # res = models.User.objects.filter(register_time__year=2017)  # sqlite對日期格式不太精准
136     # print(res)
View Code

單表查詢操作演示表2

 

1 class Book(models.Model):
2       name = models.CharField(max_length=32)
3     price = models.DecimalField(max_digits=8,decimal_place=2)
4     publish = models.CharField(max_length=32)
5     author = models.CharField(max_length=32)
6     create_time = models.DateField(null=True)
7     # 配置auto_now_add=True,創建數據記錄的時候會把當前時間添加到數據庫。
8     # 配置上auto_now=True,每次更新數據記錄的時候會更新該字段。

 

 1 新增數據
 2 
 3             # 第一種:有返回值,並且就是當前被創建的數據對象
 4         modles.Book.objects.create(name='',price='',publish='',author='',create_time='2019-5-1')
 5         # 第二種:先實例化產生對象,然后調用save方法保存
 6         book_obj = models.Book(name='',price='',publish='',author='',create_time='2019-5-1')
 7         book_obj.save()
 8         # 2.驗證時間格式字段即可以傳字符串也可以傳時間對象
 9         import datetime
10         ctime = datetime.datetime.now()
11         book = models.Book.objects.create(name='',price='',author='',create_time=ctime)
12 
13 刪除數據
14 
15             """刪除數據"""
16         # 1.刪除書名為xxx的這本書  queryset方法
17         res = models.Book.objects.filter(name='').delete()
18         print(res)
19         # 2.刪除書名為xxx的這本書  queryset方法
20         res = models.Book.objects.filter(name='').first()
21         res.delete()
22 
23 修改數據
24 
25             # 1.queryset修改
26         models.Book.objects.filter(name='').update(price='')
27         # 2.對象修改
28         book = models.Book.objects.filter(name='').first()
29         book.price = 66.66
30         book.save()  # 對象只有保存方法 這樣也能實現修改需求
31 
32 查詢數據
33 
34             <1> all():                  查詢所有結果
35         <2> filter(**kwargs):       它包含了與所給篩選條件相匹配的對象
36         <3> get(**kwargs):          返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。(源碼就去摟一眼~詮釋為何只能是一個對象)
37         <4> exclude(**kwargs):      它包含了與所給篩選條件不匹配的對象
38         <5> order_by(*field):       對查詢結果排序('-id')/('price')
39         
40         <6> reverse():              對查詢結果反向排序     >>>前面要先有排序才能反向
41         <7> count():                返回數據庫中匹配查詢(QuerySet)的對象數量。
42         <8> first():                返回第一條記錄
43         <9> last():                返回最后一條記錄
44         <10> exists():              如果QuerySet包含數據,就返回True,否則返回False
45         <11> values(*field):        返回一個ValueQuerySet——一個特殊的QuerySet,運行后得到的並不是一系列                             model的實例化對象,而是一個可迭代的字典序列
46         <12> values_list(*field):   它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
47         <13> distinct():            從返回結果中剔除重復紀錄
48     # ******************* 
49            # 必須完全一樣才可以去重(意味着帶了id就沒有意義了)
50            # res = models.Book.objects.all().values('name').distinct()  先查一個重復的值再去重
51 
52 基於雙下划線的查詢
53 
54     # 價格 大於 小於 大於等於 小於等於
55     filter(price__gt='90')
56     filter(price__lt='90')
57     filter(price_gte='90')
58     filter(price_lte='90')
59     
60     # 存在與某幾個條件中
61     filter(price__in=['11','22','33'])
62     # 在某個范圍內
63     filter(price__range=[50,90])
64     
65     # 模糊查詢
66     filter(title__contains='西')
67     filter(title__icontains='P')
68     
69     # 以什么開頭 以什么結尾
70     
71     # 按年查詢
72     filter(create_time__year='2017')
View Code

多表查詢操作演示表

 

 1 # 多表查詢表
 2 class Book(models.Model):
 3     title = models.CharField(max_length=32)
 4     price = models.DecimalField(max_digits=8,decimal_places=2)
 5     publish_date = models.DateField(auto_now_add=True)
 6     # 外鍵關系
 7     publish = models.ForeignKey(to='Publish')
 8     authors = models.ManyToManyField(to='Author')  # 虛擬字段, 信號字段
 9 
10     def __str__(self):
11         return '書籍對象的名字:%s'%self.title
12 
13 
14 class Publish(models.Model):
15     name = models.CharField(max_length=32)
16     addr = models.CharField(max_length=32)
17     email = models.EmailField()  # 對應就是varchar類型
18 
19     def __str__(self):
20         return '出版社對象的名字:%s'%self.name
21 
22 
23 class Author(models.Model):
24     name = models.CharField(max_length=32)
25     age = models.IntegerField()
26     authordetail = models.OneToOneField(to='AuthorDetail')
27 
28     def __str__(self):
29         return  '作者對象的名字:%s'%self.name
30 
31 
32 class AuthorDetail(models.Model):
33     phone = models.CharField(max_length=32)
34     addr = models.CharField(max_length=32)
  1     # 多表查詢
  2     # 新增
  3     # 直接寫id
  4     # models.Book.objects.create(title='紅樓夢',price=66.66,publish_id=1)
  5     # 傳數據對象
  6     # publish_obj = models.Publish.objects.filter(pk=2).first()
  7     # models.Book.objects.create(title='三國演義',price=199.99,publish=publish_obj)
  8 
  9     # 修改
 10     # queryset修改
 11     # models.Book.objects.filter(pk=1).update(publish_id=3)
 12     # publish_obj = models.Publish.objects.filter(pk=2).first()
 13     # models.Book.objects.filter(pk=1).update(publish=publish_obj)
 14     # 對象修改
 15     # book_obj = models.Book.objects.filter(pk=1).first()
 16     # book_obj.publish_id = 3  # 點表中真實存在的字段名
 17     # book_obj.save()
 18     # publish_obj = models.Publish.objects.filter(pk=2).first()
 19     # book_obj.publish = publish_obj  # 點orm中字段名 傳該字段對應的表的數據對象
 20     # book_obj.save()
 21 
 22     # 刪除
 23     # models.Book.objects.filter(pk=1).delete()
 24     # models.Publish.objects.filter(pk=1).delete()
 25 
 26     # book_obj = models.Book.objects.filter(pk=3).first()
 27     # book_obj.delete()
 28 
 29 
 30     # 給書籍綁定與作者之間的關系
 31     # 添加關系 add:add支持傳數字或對象,並且都可以傳多個
 32     # book_obj = models.Book.objects.filter(pk=3).first()
 33     # # book_obj.authors.add(1)
 34     # # book_obj.authors.add(2,3)
 35     # author_obj = models.Author.objects.filter(pk=1).first()
 36     # author_obj1 = models.Author.objects.filter(pk=3).first()
 37     # # book_obj.authors.add(author_obj)
 38     # book_obj.authors.add(author_obj,author_obj1)
 39 
 40     # 修改書籍與作者的關系  set()  set傳的必須是可迭代對象!!!
 41     # book_obj = models.Book.objects.filter(pk=3).first()
 42     # 可以傳數字和對象,並且支持傳多個
 43     # book_obj.authors.set((1,))
 44     # book_obj.authors.set((1,2,3))
 45     #
 46     # author_list = models.Author.objects.all()
 47     # book_obj = models.Book.objects.filter(pk=3).first()
 48     # book_obj.authors.set(author_list)
 49 
 50 
 51     # 刪除書籍與作者的綁定關系
 52     # book_obj = models.Book.objects.filter(pk=3).first()
 53     # # book_obj.authors.remove(1)
 54     # # book_obj.authors.remove(2,3)
 55     # # author_obj = models.Author.objects.all().first()
 56     # author_list = models.Author.objects.all()
 57     # # book_obj.authors.remove(author_obj)
 58     # book_obj.authors.remove(*author_list)  # 需要將queryset打散
 59 
 60 
 61     # 清空  clear()  清空的是你當前這個表記錄對應的綁定關系
 62     # book_obj = models.Book.objects.filter(pk=3).first()
 63     # book_obj.authors.clear()
 64 
 65 
 66     # 基於對象的表查詢
 67     # 正向
 68     # 查詢書籍是三國演義的出版社郵箱
 69     # book_obj = models.Book.objects.filter(title='三國演義').first()
 70     # print(book_obj.publish.email)
 71     # 查詢書籍是小王子的作者的姓名
 72     # book_obj = models.Book.objects.filter(title='小王子').first()
 73     # print(book_obj.authors)  # app01.Author.None
 74     # print(book_obj.authors.all())
 75     # 查詢作者為jason電話號碼
 76     # user_obj = models.Author.objects.filter(name='jason').first()
 77     # print(user_obj.authordetail.phone)
 78 
 79     # 反向
 80     # 查詢出版社是東方出版社出版的書籍                  一對多字段的反向查詢
 81     # publish_obj = models.Publish.objects.filter(name='東方出版社').first()
 82     # print(publish_obj.book_set)  # app01.Book.None
 83     # print(publish_obj.book_set.all())
 84 
 85     # 查詢作者jason寫過的所有的書                      多對多字段的反向查詢
 86     # author_obj = models.Author.objects.filter(name='jason').first()
 87     # print(author_obj.book_set)  # app01.Book.None
 88     # print(author_obj.book_set.all())
 89 
 90     # 查詢作者電話號碼是110的作者姓名                   一對一字段的反向查詢
 91     # authordetail_obj = models.AuthorDetail.objects.filter(phone=110).first()
 92     # print(authordetail_obj.author.name)
 93 
 94     # 基於雙下滑線的查詢
 95     # 正向
 96     # 查詢書籍為三國演義的出版社地址
 97     # res = models.Book.objects.filter(title='三國演義').values('publish__addr','title')
 98     # print(res)
 99     # 查詢書籍為小王子的作者的姓名
100     # res = models.Book.objects.filter(title='小王子').values("authors__name",'title')
101     # print(res)
102     # 查詢作者為jason的家鄉
103     # res = models.Author.objects.filter(name='jason').values('authordetail__addr')
104     # print(res)
105 
106     # 反向
107     # 查詢南方出版社出版的書名
108     # res = models.Publish.objects.filter(name='南方出版社').values('book__title')
109     # print(res)
110     # 查詢電話號碼為120的作者姓名
111     # res = models.AuthorDetail.objects.filter(phone=120).values('author__name')
112     # print(res)
113     # 查詢作者為jason的寫的書的名字
114     # res = models.Author.objects.filter(name='jason').values('book__title')
115     # print(res)
116     # 查詢書籍為三國演義的作者的電話號碼
117     # res = models.Book.objects.filter(title='三國演義').values('authors__authordetail__phone')
118     # print(res)
119 
120     # 查詢jason作者的手機號
121     # 正向
122     # res = models.Author.objects.filter(name='jason').values('authordetail__phone')
123     # print(res)
124     # 反向
125     # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
126     # print(res)
127 
128     # 查詢出版社為東方出版社的所有圖書的名字和價格
129     # 正向
130     # res = models.Publish.objects.filter(name='東方出版社').values('book__title','book__price')
131     # print(res)
132     # 反向
133     # res = models.Book.objects.filter(publish__name='東方出版社').values('title','price')
134     # print(res)
135 
136     # 查詢東方出版社出版的價格大於400的書
137     # 正向
138     # res = models.Publish.objects.filter(name="東方出版社",book__price__gt=400).values('book__title','book__price')
139     # print(res)
140     # 反向
141     # res = models.Book.objects.filter(price__gt=400,publish__name='東方出版社').values('title','price')
142     # print(res)
143 
144 
145 
146     # 聚合查詢  aggregate
147     from django.db.models import Max,Min,Count,Sum,Avg
148     # 查詢所有書籍的作者個數
149     # res = models.Book.objects.filter(pk=3).aggregate(count_num=Count('authors'))
150     # print(res)
151     # 查詢所有出版社出版的書的平均價格
152     # res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
153     # print(res)  # 4498.636
154     # 統計東方出版社出版的書籍的個數
155     # res = models.Publish.objects.filter(name='東方出版社').aggregate(count_num=Count('book__id'))
156     # print(res)
157 
158 
159     # 分組查詢(group_by)   annotate
160     # 統計每個出版社出版的書的平均價格
161     # res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
162     # print(res)
163     # 統計每一本書的作者個數
164     # res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')
165     # print(res)
166     # 統計出每個出版社賣的最便宜的書的價格
167     # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
168     # print(res)
169     # 查詢每個作者出的書的總價格
170     # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
171     # print(res)
View Code

 

創建圖書管理系統表(給作者表加一張作者詳情表為了一對一的查詢),詮釋一對一關聯其實就是外健關聯再加一個唯一性約束而已

ForeignKey(unique=Ture) >>> OneToOneField()
# 即一對一可以用ForeignKey來做,但是需要設唯一性約束並且會報警告信息,不建議使用,建議用OneToOneField
# 用了OneToOneField和用ForeignKey會自動在字段后面加_id
# 用了ManyToMany會自動創建第三張表

 

一對多的書籍記錄增刪改查

# 針對外鍵關聯的字段 兩種添加方式
# 第一種通過publish_id
# 第二種通過publish傳出版社對象

# 刪除書籍直接查詢刪除即可,刪除出版社會級聯刪除

# 編輯數據也是兩種對應的方式(對象點的方式(這里能點publish和publish_id)最后點save(),queryset方式update())

多對多的書籍與作者的增刪改查

"""前提:先獲取書籍對象,再通過書籍對象點authors來進行書籍作者的增刪改查"""
# 1.給書籍新增作者add
# 1.add可以傳作者id,也可以直接傳作者對象,並且支持傳多個位置參數(不要混着用)

# 2.給書籍刪除作者remove
# 1.remove同樣可以傳id,對象,並且支持傳多個位置參數(不要混着用)

# 3.直接清空書籍對象所有的作者數據clear()不用傳任何參數

# 4.修改書籍對象所關聯的作者信息set,注意點set括號內必須傳可迭代對象,里面可以傳id,對象

"""總結:一對多增刪改,多對多add,remove,clear,set"""

正向反向概念

# 正向與方向的概念解釋

# 一對一
# 正向:author---關聯字段在author表里--->authordetail 按字段
# 反向:authordetail---關聯字段在author表里--->author 按表名小寫
# 查詢jason作者的手機號 正向查詢
# 查詢地址是 :山東 的作者名字 反向查詢

# 一對多
# 正向:book---關聯字段在book表里--->publish 按字段
# 反向:publish---關聯字段在book表里--->book 按表名小寫_set.all() 因為一個出版社對應着多個圖書

# 多對多
# 正向:book---關聯字段在book表里--->author 按字段
# 反向:author---關聯字段在book表里--->book 按表名小寫_set.all() 因為一個作者對應着多個圖書

# 連續跨表
# 查詢圖書是三國演義的作者的手機號,先查書,再正向查到作者,在正向查手機號

# 總結:基於對象的查詢都是子查詢,這里可以用django配置文件自動打印sql語句的配置做演示

基於雙下划線的查詢

 

# 一對一
-連表查詢
-一對一雙下划線查詢
-正向:按字段,跨表可以在filter,也可以在values中
-反向:按表名小寫,跨表可以在filter,也可以在values中
# 查詢jason作者的手機號 正向查詢 跨表的話,按字段
# ret=Author.objects.filter(name='jason').values('authordetail__phone')
# 以authordetail作為基表 反向查詢,按表名小寫 跨表的話,用表名小寫
# ret=AuthorDetail.objects.filter(author__name='jason').values('phone')

# 查詢jason這個作者的性別和手機號
# 正向
# ret=Author.objects.filter(name='jason').values('sex','authordetail__phone')

 

# 查詢手機號是13888888的作者性別
# ret=Author.objects.filter(authordetail__phone='13888888').values('sex')
# ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex')

"""
總結 其實你在查詢的時候先把orm查詢語句寫出來,再看用到的條件是否在當前表內,在就直接獲取,不在就按照正向按字段反向按表名來查即可
比如:
1.查詢出版社為北方出版社的所有圖書的名字和價格
res1 = Publish.objects.filter(name='').values('book__name','book__price')
res2 = Book.objects.filter(publish__name='').values('name','price')
2.查詢北方出版社出版的價格大於19的書
res1 = Publish.objects.filter(name='',book__price__gt=19).values('book__name','book__price)
"""

再次強調:

  1. 對於所有類型的關聯字段,add()、create()、remove()和clear(),set()都會馬上更新數據庫。換句話說,在關聯的任何一端,都不需要再調用save()方法。

聚合查詢和分組查詢

聚合(利用聚合函數)

aggregate()QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。

鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。

用到的內置函數:

from django.db.models import Avg, Sum, Max, Min, Count

示例:

>>> from django.db.models import Avg, Sum, Max, Min, Count
>>> models.Book.objects.all().aggregate(Avg("price"))
{'price__avg': 13.233333}

如果你想要為聚合值指定一個名稱,可以向聚合子句提供它。

>>> models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 13.233333}

如果你希望生成不止一個聚合,你可以向aggregate()子句中添加另一個參數。所以,如果你也想知道所有圖書價格的最大值和最小值,可以這樣查詢:

>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}

分組

我們在這里先復習一下SQL語句的分組。

假設現在有一張公司職員表:

 我們使用原生SQL語句,按照部分分組求平均工資:

select dept,AVG(salary) from employee group by dept;

ORM查詢:

from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
這里需要注意的是annotate分組依據就是他前面的值,
如果前面沒有特點的字段,則默認按照ID分組,
這里有dept字段,所以按照dept字段分組

連表查詢的分組:

SQL查詢:

select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;

ORM查詢:

from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

更多示例:

示例1:統計每一本書的作者個數

>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> for obj in book_list:
...     print(obj.author_num)
...
1

示例2:統計出每個出版社買的最便宜的書的價格

 
 
>>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
>>> for obj in publisher_list:
...     print(obj.min_price)
...     
9.90
19.90
 
 

方法二:

>>> models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
<QuerySet [{'publisher__name': '沙河出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>

示例3:統計不止一個作者的圖書

>>> models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
<QuerySet [<Book: 番茄物語>]>

示例4:根據一本圖書作者數量的多少對查詢集 QuerySet進行排序

>>> models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
<QuerySet [<Book: 香蕉物語>, <Book: 橘子物語>, <Book: 番茄物語>]>

示例5:查詢各個作者出的書的總價格

1 >>> models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
2 <QuerySet [{'name': '小精靈', 'sum_price': Decimal('9.90')}, {'name': '小仙女', 'sum_price': Decimal('29.80')}, {'name': '小魔女', 'sum_price': Decimal('9.90')}]>
View Code

 

 總結

value里面的參數對應的是sql語句中的select要查找顯示的字段,

filter里面的參數相當於where或者having里面的篩選條件

annotate本身表示group by的作用,前面找尋分組依據,內部放置顯示可能用到的聚合運算式,后面跟filter來增加限制條件,最后的value來表示分組后想要查找的字段值

 最后的小總結

模型層ORM
ORM操作
class User(models.Model):
name = models.CharField(max_length=32)
...

def save(self):
# 在對象調用save保存到數據庫之前,在這里可以攔截進行相應的操作
super().save()

def delete(self):
# 在對象調用delete刪除數據之前,在這里可以攔截進行相應的操作
super().delete()

單表操作

# 方式1:
user_obj = models.User.objects.create(**kwargs) # 注意create方法有返回值,並且就是新建數據對象本身
# 方式2:
user_obj = models.User(**kwargs)
user_obj.save()

models.User.objects.filter(**kwargs) # 多個過濾條件是and關系
models.User.objects.get() # 不推薦使用
models.User.objects.all() # 惰性查詢

models.User.objects.filter(**kwargs).update(**kwargs) # 批量更新

user_obj = models.User.objects.filter(**kwargs).first()
user_obj.name = 'jason'
user_obj.save()
user_obj.update() # 對象沒有點update的方法

models.User.objects.filter(**kwargs).delete() # 批量刪除

user_obj = models.User.objects.filter(**kwargs).first()
user_obj.delete()

多表操作
如何確立表關系:
一個A能否有多個B
一個B能否有對個A

如果兩者都能那么就是 多對多
如果只有一方可以 一對多
如果雙方都不可以但是兩者卻有關系 一對一



表關系:
一對一(OneToOneField):無論建在哪一方都可以,但是推薦建在查詢頻率較高的一方
一對多(ForeignKey):建在多的那一方
多對多(ManyToManyField):無論建在哪一方都可以,但是推薦建在查詢頻率較高的一方

外鍵字段的增刪改查
一對多字段的增刪改查(publish)

models.Book.objects.create(publish_id=1)

publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(publish=publish_obj)



book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish = new_publish_obj

book_obj = models.Book.objects.filter(pk=1).update(publish_id=2)
book_obj = models.Book.objects.filter(pk=1).update(publish=publish_obj)


刪除書籍正常刪除
刪除出版社那么會級聯刪除改出版社對應的所有的書籍

多對多字段增刪改查

add()

set()

remove()

# 上面三個方法都可以支持傳多個數字或對象,set必須接收一個可迭代對象
清空
clear()
跨表表查詢
正向反向
關聯字段在你當前這表查詢另一張叫正向
關聯字段不在你當前這表查詢另一張叫反向
總結:正向查詢按字段,反向查詢按表名小寫(******)

# 基於對象的跨表查詢(子查詢)
# 基於雙下划線的跨表查詢(聯表查詢)

基於對象
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish.addr
book_obj.publish.name
book_obj.authors.all()

publish_obj = models.Publish.objects.filter(pk=1).first()
publish_obj.book_set.all()


基於雙下划線的跨表查詢
res = models.Book.objects.filter(publish__name='東方出版社',title='小王子').values('title','publish__name','authors__authordetail__phone')



settings文件配置
直接拷貝使用即可

queryset對象.query也能夠查看內部對應的sql語句
all()
filter()
values()
value_list()
order_by()
reverse()
distinct()
exclude()


count() 計數
exists() 布爾值
get() 數據對象本身
first()
last()


聚合查詢
from django.db.models import Max,Min,Sum,Count,Avg
aggragate()

分組查詢(group by)
annotate() group_concat() concat()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM