Django ORM 常用字段和參數


1、常用字段

AutoFiled

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

IntegerField

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

CharField

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

這里需要知道的是Django中的CharField對應的MySQL數據庫中的varchar類型,沒有設置對應char類型的字段,但是Django允許我們自定義新的字段,下面我來自定義對應於數據庫的char類型

自定義char字段:

from django.db import models

class MyCharField(models.Field):
    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super().__init__(max_length=max_length,*args, **kwargs)
    def db_type(self, connection):
        return 'char(%s)' % self.max_length

class MyModel(models.Model):
    my_field = MyCharField(32)    

  

 

DateField

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

 

DateTimeField

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

 

2、字段參數

null

       用於表示某個字段可以為空, null=True

unique

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

db_index

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

default

  為該字段設置默認值

 

1.3  DateFiled 和 DateTimeFiled 里的參數

auto_now_add

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

auto_now

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

 

2、關系字段

2.1 ForeignKey

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

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

 字段參數

to : 設置要關聯的表

to_field : 設置要關聯的表的字段

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

models.CASCADE : django  2.0 版本后必須加上后,刪除關聯數據,與之關聯的數據也會被刪除,在2.0以前,系統默認加上了

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

 

2.2  OneToOneField

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

字段參數:

to : 設置要關聯的表

to_field : 設置要關聯的字段

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

 

3、在app下的tests文件下進行運行測試,配置相關參數如下

import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings")
import django
django.setup()
from app01 import models # 這一句話必須在這下面導入

 

4、對表數據的增刪改

新增

    基於create創建
    user_obj = models.User.objects.create(name='json',age=28,register_time='2019-6-6')
    print(user_obj.register_time)
    基於save創建
    user_obj = models.User(name='tank',age=10,register_time='2014-3-1')
    user_obj.save()

    from datetime import datetime
    ctime = datetime.now()
    models.User.objects.create(name='tank',age=22,register_time=ctime)

修改
    方式一  基於對象
    user_obj = models.User.objects.filter(name='michael').first()
    # print(user_obj,type(user_obj))
    user_obj.age = 24
    user_obj.save()
    方式二 基於queryset
    models.User.objects.filter(name='egon').update(age=36)


刪除
    基於queryset
    models.User.objects.filter(name='tank').delete()
    基於對象
    user_obj = models.User.objects.filter(name='tank').first()
    user_obj.delete()
增刪改

 

5、單表查詢

<1> all():                  查詢所有結果
<2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象 <3> get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。 <4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象 <5> order_by(*field): 對查詢結果排序('-id')/('price') <6> reverse(): 對查詢結果反向排序 >>>前面要先有排序才能反向 <7> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。 <8> first(): 返回第一條記錄 <9> last(): 返回最后一條記錄 <10> exists(): 如果QuerySet包含數據,就返回True,否則返回False <11> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行后得到的是列表套字典 <12> values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列 <13> distinct(): 從返回結果中剔除重復紀錄
  < 4 > exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象
    res = models.User.objects.exclude(name='cwj')    #queryset對象

< 6 > reverse(): 對查詢結果反向排序 >> > 前面要先有排序才能反向
    res= models.User.objects.order_by('age').reverse()

 < 7 > count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。
    user_obj = models.User.objects.all().count()

 < 10 > exists(): 如果QuerySet包含數據,就返回True,否則返回False
    user_obj = models.User.objects.filter(name='michael').exists()
    print(user_obj,type(user_obj))  #True <class 'bool'>

    < 11 > values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行后得到的並不是一系列model的實例化對象,而是一個可迭代的字典序列
    user_obj = models.User.objects.values('name')
    print(user_obj)  #<QuerySet [{'name': 'michael'}, {'name': 'egon'}, {'name': 'owen'}, {'name': 'mac'}, {'name': 'json'}]>


    < 12 > values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
    user_obj = models.User.objects.values_list('name')
    print(user_obj) #<QuerySet [('michael',), ('egon',), ('owen',), ('mac',), ('json',)]>


   < 13 > distinct(): 從返回結果中剔除重復紀錄,去重的對象必須完全相同,即前面的返回值必須是一樣的,與filter搭配沒效果
    res = models.User.objects.values('name').distinct()
    print(res)
例子

 

6 單表查詢的雙下划線查詢

   1、查詢年齡大於28歲的用戶
    res = models.User.objects.filter(age__gt=28)
    print(res)

    2、查詢年齡年齡小於28歲的用戶
    res = models.User.objects.filter(age__lt=28)
    print(res)

    3、查詢年齡大於等於28歲的用戶
    res = models.User.objects.filter(age__gte=28)
    print(res)

    4、查詢年齡小於等於28歲的用戶
    res = models.User.objects.filter(age__lte=28)
    print(res)

    5、查詢年齡是36 16 18的用戶
    res = models.User.objects.filter(age__in=[36 ,16 ,18])

    6、查詢年齡在18到28的用戶
    res = models.User.objects.filter(age__range=[18,28])

    7、查詢名字中包含字母
    res = models.User.objects.filter(name__contains='E')
    print(res)
    在數據庫sqlite里無法體現
    res = models.User.objects.filter(name__icontains='E')  無視大小寫
    print(res)

    8、查詢名字以m開頭的用戶
    res = models.User.objects.filter(name__startswith='m')

    9、查詢名字以n結尾的用戶
    res = models.User.objects.filter(name__endswith='n')

    10、查詢注冊時間是2018年的用戶
    res = models.User.objects.filter(register_time__year= 2018)
    print(res)

 

 

7、返回對象的總結

返回QuerySet對象的方法有:
all()

filter()

exclude()

order_by()

reverse()

distinct()

特殊的QuerySet

values()       返回一個可迭代的字典序列

values_list() 返回一個可迭代的元祖序列

返回具體對象的
get()

first()

last()

返回布爾值的方法有:
exists()

返回數字的方法有:
count()

  

8、Django 終端打印SQL語句


如果想知道對數據庫進行操作時,Django內部到底是怎么執行它的sql語句時可以加下面的配置來查看

在Django項目的settings.py文件中,復制粘貼如下代碼:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}


配置好之后,再執行任何對數據庫進行操作的語句時,會自動將Django執行的sql語句打印到pycharm終端上


補充:除了配置外,還可以通過點.query 來查看查詢語句!

  

9、多表查詢

表與表之間的關系
一對一(OneToOneField):一對一字段無論建在哪張關系表里面都可以,但是推薦建在查詢頻率比較高的那張表里面
一對多(ForeignKey):一對多字段建在多的那一方
多對多(ManyToManyField):多對多字段無論建在哪張關系表里面都可以,但是推薦建在查詢頻率比較高的那張表里面
ps:如何判斷表與表之間到底是什么關系
換位思考
A能不能有多個B
B能不能有多個A

多表查詢的方法:

create()

創建一個關聯對象,並自動寫入數據庫,且在第三張雙方的關聯表中自動新建上雙方對應關系。

models.Author.objects.first().book_set.create(title="偷塔秘籍")
上面這一句干了哪些事兒:
1.由作者表中的一個對象跨到書籍比表
2.新增名為偷塔秘籍的書籍並保存
3.到作者與書籍的第三張表中新增兩者之間的多對多關系並保存
add()

把指定的model對象添加到第三張關聯表中。

添加對象

>>> author_objs = models.Author.objects.filter(id__lt=3)
>>> models.Book.objects.first().authors.add(*author_objs)
添加id

>>> models.Book.objects.first().authors.add(*[1, 2])
set()

更新某個對象在第三張表中的關聯對象。不同於上面的add是添加,set相當於重置

>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.set([2, 3])
remove()

從關聯對象集中移除執行的model對象(移除對象在第三張表中與某個關聯對象的關系)

>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.remove(3)
clear()

從關聯對象集中移除一切對象。(移除所有與對象相關的關系信息)

>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.clear()
#1、給書籍綁定與作者的關系
    # book_obj = models.Book.objects.filter(pk=2).first()
    # print(type(book_obj),book_obj)
    # book_obj.author.add(4)

    # author_obj = models.Author.objects.filter(pk=1).first()
    # author_obj1 = models.Author.objects.filter(pk=3).first()
    # book_obj = models.Book.objects.filter(pk=4).first()
    # # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.author.add(author_obj,author_obj1)
    # # 添加關系 add:add支持傳數字或對象,並且都可以傳多個


#2、修改書籍與作者之間的關系  可以傳數字和對象,並且支持傳多個  數據對應關系存在與否都無所謂
    # book_obj = models.Book.objects.filter(pk=3).first()
    # book_obj.author.set((2,))
    # set會將修改的數據id重新生成,之前的id被刪除,但是會占位
    # book_obj = models.Book.objects.filter(pk=2).first()
    # author_obj = models.Author.objects.filter(pk=1).first()
    # author_obj1 = models.Author.objects.filter(pk=2).first()
    # book_obj.author.set((author_obj1,author_obj))


# 3、刪除書籍和作者的綁定關系 remove   建立在數據關系已存在的基礎上
#     book_obj = models.Book.objects.filter(pk=2).first()
#     book_obj.author.remove(1)

    # book_obj = models.Book.objects.filter(pk=1).first()
    # author_list = models.Author.objects.all()
    # book_obj.author.remove(*author_list)  #需要將queryset打散


#4、清空 清空的是你當前這個表記錄對應的綁定關系
    # book_obj = models.Book.objects.filter(pk=4).first()
    # book_obj.author.clear()  #直接將與book的id 為4 所對應的author 全刪除,更加果斷!
View Code

 

多表查詢:   即只要前者是正常的對象就可以繼續查下去

  #1、地址為西湖的作者的書  反向再反向
    # author_obj = models.AuthorDetail.objects.filter(addr='西湖').first()
    # # print(author_obj.author.book_set.all())
    # print(type(author_obj))
    # print(type(author_obj.author))    #正向直接點是對象
    # print(type(author_obj.author.book_set))  #反向點是  多對多的對象
    # print(type(author_obj.author.book_set.all())) #加上all()是queryset對象

    # 2、查詢書籍凡人修仙傳的作者的地址      正向再正向
    # book_obj = models.Book.objects.filter(title='凡人修仙傳').first()
    # print(book_obj.author.all().authordetail.addr)   涉及到對多的情況后無法繼續查詢
    # print(type(book_obj))  #book的對象
    # print(type(book_obj.author))  #多對多的對象
    # print(type(book_obj.publish)) #publish的對象
    # print(type(book_obj.author.all()))  #queryset的對象

    # 3、通過作者的地址查詢出對應的書籍  反向在反向
    # author_obj = models.AuthorDetail.objects.filter(addr='西湖').first()
    # print(author_obj.author.book_set.all())
    # print(type(author_obj))    authordetail的對象
    # print(type(author_obj.author))  author的對象
    # print(type(author_obj.author.book_set)) 對多的對象
    # print(type(author_obj.author.book_set.all())) queryset對象
基於雙下划線查詢

#正向
    # 查詢書籍為蝸居的出版社地址
    # res = models.Book.objects.filter(title='蝸居').values('publish__addr','price')
    # print(type(res))   <class 'django.db.models.query.QuerySet'>
    # print(res)  <QuerySet [{'publish__addr': '北京', 'price': Decimal('28.66')}]>

    #查詢書籍為長征的作者的姓名,地址
    # res = models.Book.objects.filter(title='長征').values('author__name','author__authordetail__addr')
    # print(res)

    # book_obj = models.Book.objects.filter(title='長征').first()
    # print(book_obj.author.all().authordetail.addr)  #無法查詢,對象點 適合兩表查詢

    #查詢michael的家鄉
    # res = models.Author.objects.filter(name='michael').values('authordetail__addr')
    # print(res)


    #反向

    # # 查詢南方出版社出版的書名,書對應的作者
    # res = models.Publish.objects.filter(name='南方出版社').values('book__title','book__author__name')
    # print(res)

    # 不管正向還是方向,只要有聯系,就可以找到,好用

    # 查詢出版社為東方出版社的所有圖書的名字和價格
    # res = models.Publish.objects.filter(name='東方出版社').values('book__title','book__price','book__author__authordetail_id')
    # print(res)

    # 查詢東方出版社出版的價格大於400的書
    # res = models.Publish.objects.filter(name='東方出版社',book__price__gt=100).values('book__title')
    # print(res)

  

  

10、聚合查詢和分組查詢

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')}


分組查詢:
示例:

>> 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: 番茄物語>]>

 

   例子:

# 統計每個出版社出版的書的平均價格
# res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name', 'avg_price')
# print(res)


#統計每一本書的作者個數
# res = models.Book.objects.annotate(count_num=Count('author')).values('title','count_num')
# print(res)

#統計每個出版社賣的zui最便宜的書的價格
# res = models.Publish.objects.annotate(min=Min('book__price')).values('name','min')
# print(res)

#查詢每個作者出的書的總價格
# res = models.Author.objects.annotate(sum=Sum('book__price')).values('name','sum')
# print(res)

  

 總結

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

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

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

 

 

 

 

 

 

 

 


免責聲明!

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



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