Django5_model模型

一.ORM
ORM:Object Relational Mapping(關係對象映射)
咱們經過寫的類來表示數據庫中的表;
咱們根據這個類建立的對象是數據庫表裏的一行數據;
做用:爲了實現面向對象的編程語言裏不一樣類型系統的數據之間進行轉換,即:用面向對象的方式去操做數據庫進行建立表及增刪改查等操做;
好處:1.ORM使得咱們通用的數據庫進行交互是變得簡單易行,並且徹底不用考慮不一樣的SQL語句。可以快速開發;2.能夠避免一些對數據庫操做不熟帶來的因爲手寫sql語句帶來的性能問題;
二.Django不能數據庫的使用
1.django默認使用sqlite數據庫驅動引擎(不用進行任何配置),若是要使用MySQL數據庫,則須要修改ettings.py中的DATABASES;python

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'day70',
    'USER': 'eric',
    'PASSWORD': '123123',
    'HOST': '192.168.182.128',
    'PORT': '3306',
    }
}

2.若查看orm操做執行的原生SQL語句,在project中的settings.py文件增長配置文件mysql

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

3.修改project 中的initpy 文件設置 Django默認鏈接MySQL的方式:git

import pymysql
pymysql.install_as_MySQLdb()

三.表的建立
A.首先在項目的setting文件中設置DATABASES的參數(數據庫參數配置);
B.若是是非sqlite數據庫,則須要在對應的app應用下導入對應的數據庫模塊;
C.在對應APP應用下的model下添加須要建立表對應的classs;
1.單表的建立sql

class Userinfo(models.Model):
    username = models.CharField(max_length=256,primary_key=True)
    password = models.CharField(max_length=256)
    address = models.CharField(max_length=256)
    age = models.IntegerField()

2.一對多表的建立數據庫

class Book(models.Model):
    # 從表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
    pub_date=models.DateField()
 publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

3.多對多表的建立
3.1方式1:使用ManyToManyField()方法進行關聯多對多(此時在django中會自動生成第三張表book_author)django

from django.db import models

# Create your models here.
class Book(models.Model):
    # 從表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
 publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    #建立Book和Authors的多對多關係
    authors = models.ManyToManyField("Authors")

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

Django5_model模型
3.2方式2:不使用ManyToManyField()方法,手動建立第三張book_author關聯的表(一對多的關係)編程

from django.db import models
# Create your models here.
class Book(models.Model):
    # 從表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
 publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
#手動建立第三張關聯Book和Author的表Book_Author(此時ManyToManyField()不能再用)
class Book_Author(models.Model):
    bookid = models.ForeignKey("Book",on_delete=models.CASCADE)
    authors = models.ForeignKey("Authors",on_delete=models.CASCADE)

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

Django5_model模型
四.單表數據庫增刪改查
2.1增:向數據庫中添加數據
方式1.使用model中的對象並結合object的create方法
Userinfo.objects.create(username ='username',password = 'password',address = 'address',age = 34)
方式2.使用model中的類進行實例化進行操做
該方法是先使用model類進行實例化,再使用save進行保存緩存

user = Userinfo(username = 'username',password = 'password',address = 'address',age = 'age')
 user.save()

2.2刪:刪除數據庫中的數據(先使用filter進行查詢再刪除)
Userinfo.objects.filter(username=username).delete()
2.3改:修改數據庫中現有的數據(先使用filter進行查詢再進行修改)
方式1:app

Userinfo.objects.filter(username=username).update(password="password",address = "address")
Sql:update tablename set password="password",address = "address" where username=username

方式2:編程語言

User = Userinfo.objects.filter(username=username)
User.password="password"
User.address ="address"
User.save()
Sql:update tablename set password="password",address = "address",age = "age" where username=username

方式1與方式2的區別:
方式1只修改指定的字段值,而方式2會修改全部字段的值(指定了新值則使用新值,沒有新值則使用原有的值);方式2操做更復雜且效率低;
2.3查:按照條件查詢數據庫
A.判斷查詢結果是否有值(結果爲布爾值,查詢結果又記錄返回Ture,不然返回False)
Userinfo.objects.filter(username=request.POST.get('username')).exists()
B.查詢某個表的全部記錄
Userinfo.objects.all()
C.查詢某個表結果的N條記錄

Userinfo.objects.all()[0]
Userinfo.objects.all()[:]
Userinfo.objects.all()[:4]
Userinfo.objects.all()[: : 1]
Userinfo.objects.all()[:4: -1]
Userinfo.objects.first()--獲取查詢結果第1條,結果爲實例對象
Userinfo.objects.laset()--獲取查詢結果最後1條,結果爲實例對象

D.查詢字段值等於某個值(=)

Userinfo.objects.filter(username=username)

E.查詢字段值不等於某個值(!=)

Userinfo.objects.exclude(username='admin1')

F.查詢字段值包含某些值(in)

Userinfo.objects.filter(age__in =[34,55,56])
Sql: select * from table where age in (34,55,56 )

G.查詢字段值不包含某些值(not in)

Userinfo.objects.exclude(age__in =[34,55,56])
Sql: select * from table where age not in (34,55,56 )

H.查詢字段值大於或大於等於某個值(>或>=)

Userinfo.objects.filter(age__gt =34)
Sql: select * from table where age > 34;
Userinfo.objects.filter(age__gte =34)
Sql: select * from table where age >= 34;

I.查詢字段值小於或小於等於某個值(<或<=)

Userinfo.objects.filter(age__lt =34)
Sql: select * from table where age < 34;
Userinfo.objects.filter(age__lte =34)
Sql: select * from table where age <= 34;

J.查詢字段值包含某個值(like)
1.不忽略大小寫的模糊查詢 like ‘%zh%’

Userinfo.objects.filter(username__contains ='zh')

2.忽略大小寫的模糊查詢 忽略大小寫 like ‘%zh%’

Userinfo.objects.filter(username__icontains ='zh')

3.以...開頭

Userinfo.objects.filter(username__startswith = 'z')

4.以...開頭並忽略大小寫

Userinfo.objects.filter(username__istartswith = 'z')

5.以...結尾

Userinfo.objects.filter(username__endswith ='g')

6.以...結尾並忽略大小寫

Userinfo.objects.filter(username__iendswith ='g')

注:對於sqlite來講,contains的做用效果等同於icontains
K.查詢字段值不包含某個值(not like)

Userinfo.objects.exclude(username__contains = 'zh')

L.查詢字段值在某個範圍以內(between and)

方式1.Userinfo.objects.filter(age__gt = 30,age__lt = 60)
方式2.Userinfo.objects.filter(age__range = [34,56])(包含邊界)

M.查詢須要字段的結果

方式1:
Userinfo.objects.filter(username=username).values("username","password","address","age")
獲得的是一個QuerySet(字典類型)類型的list
方式2:
Userinfo.objects.filter(username=username).values_list("username","password","address","age")
獲得的是一個QuerySet(元組類型)類型的list

N.對查詢結果去重

Userinfo.objects.filter(username__icontains='zh').distinct()
Sql:select distinct * from tablename where username like 'zh';

O.對查詢結果進行統計

Userinfo.objects.filter(username__icontains='zh').count()
Sql:select count(*) from tablename where username like 'zh';

P.year 日期字段的年份
Q.month 日期字段的月份
R.day 日期字段的日
S.isnull=True/False
T.isnull=True 與 exact=None的區別

查詢的另外一種方式:

Userinfo.objects.get(username = 'zhang')

只使用於有且只有一個條結果,不然將會報錯。
經過filter()方法和get()方法查詢的區別:
1.filter()的查詢結果能夠爲任意狀況(可有,可無,可惟一,可多條);而get()方法只適用於只有一條結果的狀況;
2.filter()獲得的查詢結果爲一個QuerySet的list,而get()方法獲得的結果爲一個實例化的對象(不能進行遍歷)

users = Userinfo.objects.get(username = 'zhang')
uame=users.username
users = Userinfo.objects.all()
uame2=users[0].username

五.一對多表的操做
A表中一條數據對應B表中N條數據,B表中已條數據只能對應A表中一條數據- - - -一對多;
Django5_model模型
Django5_model模型
多表操做也包含增刪改查,主要與單表大體相同。注意一對多查詢中的技巧便可。如下講解查詢的主要方法,也是多表操做中的重難點。
A.新增
方式1.直接給外鍵賦值對應的數值
新增
# 方式1.外鍵直接賦值數值

Book.objects.create(title = 'Javascript經典',price = 67.2,pub_date = '2017-12-02',publish_id =1)

方式2.給外鍵賦值對應的主鍵對象(django內部翻譯對應的外鍵)

# 方式2.外鍵賦值對應的主鍵對象
publish = Publish.objects.get(name='清華出版社')
Book.objects.create(title='python從入門到放棄', price=87.2, pub_date='2014-12-02', publish=publish)

B.查詢
1.查看屬性值

books = Book.objects.get(title=bookname)
print("title=",books.title)

2.正向查詢(經過從表外鍵屬性查看主表的各個字段值)

books = Book.objects.get(title=bookname)
print("publish=",books.publish)
print("type=", type(books.publish))
print("publishname=",books.publish.name)    #正向查詢

如圖:
Django5_model模型
3.經過從表的外鍵查詢對應的主表的對應內容

#方式1.經過從表的外鍵值等於主表的主鍵進行關聯
bookpublishs = Publish.objects.filter(id = Book.objects.get(title=bookname).publish_id)
# 方式2.經過主表和從表的關聯用從表的某一個字段來查詢對應主表的信息
bookpublishs1  =  Publish.objects.filter(book__title__icontains='入門')

Django5_model模型
*4.經過主表來查詢對應從表的信息(確定多條結果)重點**

# 方式1.經過主表的主鍵與從表的外鍵相等的屬性進行關聯查詢(複雜)
books = Book.objects.filter(publish_id=Publish.objects.get(name=publishname).id)
#方式2.經過從表外鍵屬性來查詢出對應主表主鍵對應的從表全部信息(即:查找出某出版社全部書籍的信息)(推薦使用)
books = Book.objects.filter(publish =Publish.objects.get(name = publishname))
# 方式3.經過主表查詢全部對應從表的記錄(obj_set關鍵字,推薦使用)
publish = Publish.objects.get(name = publishname)
books = publish.book_set.all()
#方式4.經過從表的外鍵之萬能雙下劃線(__)進行關聯主表查詢
books1 = Book.objects.filter(publish__name=publishname)
# 方式5.經過主表和從表的關聯用從表對象的萬能雙下劃線(__)進行關聯從表進行查詢
booknames = Publish.objects.filter(name='南方出版社').values('book__title','book__price')

Django5_model模型
Django5_model模型
六.多對多表的操做
A.方式1(ManyToManyField()方法)關聯

from django.db import models

# Create your models here.
class Book(models.Model):
    # 從表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)

    #建立Book和Authors的多對多關係
    authors = models.ManyToManyField("Authors")

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

新增:

#新增Book和Authors之間的關聯,即:新增第三張關聯表的記錄
#找到須要進行關聯的book(進行關聯時必須是一條記錄)
book_obj = Book.objects.filter(title__contains='經典')[0]
# 找到book須要進行關聯的authors
author_objs = Authors.objects.filter(age__lt=56)
author_obj = Authors.objects.get(id=1)      #獲得一條記錄
#將book和authors進行關聯
book_obj.authors.add(*author_objs)#author_obj獲得的是一個相似列表的集合,因此此處要在前面加*;若是獲得的是一條記錄則不用加*
book_obj.authors.add(author_obj)

查詢:

#經過book查詢authors
book = Book.objects.filter(id=1).all()[0]
authors = book.authors.all()
for i in range(len(authors)):
    print("book",authors[i].name,authors[i].age)

# 經過authors查詢book
auth = Authors.objects.filter(id=1).all()[0]
book = auth.book_set.all()
for i in range(len(book)):
    print("book",book[i].title,book[i].publish)

# 查詢'再遇未知的本身'書的做者
info =Authors.objects.filter(book__title='再遇未知的本身').values('name','age','book__title','book__price')

刪除:

#同理,解除book和authors之間的關聯
# 找到須要進行關聯的book(進行關聯時必須是一條記錄)
book_obj = Book.objects.filter(title__contains='經典')[0]
# 找到book須要進行關聯的authors
author_objs = Authors.objects.filter(age__lt=56)
author_obj = Authors.objects.get(id=1)  # 獲得一條記錄
#解除book和authors之間的關聯
book_obj.authors.remove(author_obj)     #解除一條關聯的記錄(不帶*)
book_obj.authors.remove(*author_objs)   #解除多條關聯的記錄(帶*)
book_obj.authors.remove(3)      #解除一條關聯的記錄(authors_id = 3)

修改:
參考一對多表的修改操做
B.手動建立第三張關聯表(Book_Author)進行關聯(*不推薦使用)
說明:不推薦該種方式,由於經過手動建立第三張關聯的表,將不會在Book表中建立author的實例屬性,不能直接使用萬能的’__’方式來經過book調用author的相關屬性,不方便操做。

from django.db import models

# Create your models here.
class Book(models.Model):
    # 從表
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
    pub_date=models.DateField()
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)

    #建立Book和Authors的多對多關係
    # authors = models.ManyToManyField("Authors")

#手動建立第三張關聯Book和Author的表Book_Author(此時ManyToManyField()不能再用)
class Book_Author(models.Model):
    book = models.ForeignKey("Book",on_delete=models.CASCADE)
    authors = models.ForeignKey("Authors",on_delete=models.CASCADE)

class Publish(models.Model):
    # 主表
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

class Authors(models.Model):
    name = models.CharField(max_length=64)
    age = models.IntegerField()
    sex = models.CharField(max_length=32)

新增:

Book_Author.objects.create(book_id = 1,authors_id=2)

查詢:

#查詢
#查詢'再遇未知的本身'書的做者
#方式1:
book = Book.objects.get(title='再遇未知的本身')
authors =  book.book_author_set.all().values('authors__name')
# print("authors=",authors[0]['authors__name'])
# 方式2:
authors = book.book_author_set.all()[0].authors.name
#查詢'劉漢英'出過的書
authors = Authors.objects.get(name='劉漢英')
book = authors.book_author_set.all().values('book__title','book__price')

修改:
刪除:

七.model數據庫的聚合函數及分組函數的使用方法
聚合函數包含:Sum() Max() Min() Avg() Count()......
分組函數: group by
Django中聚合函數的格式:
Book.objects.all().aggregate(自定義別名 = 聚合函數名稱("字段名稱"))
例如:

price = Book.objects.all().aggregate(Avg("price"))
sum = Book.objects.all().aggregate(Sum("price"))
count = Book.objects.all().aggregate(Count("price"))
max = Book.objects.all().aggregate(Max("price"))
min = Book.objects.all().aggregate(Min("price"))

price = Book.objects.filter(authors__name='劉漢英').aggregate(Avg("price"))

Django5_model模型

Django5_model模型

Django中分組函數的格式:
Book.objects.all().values("分組的字段").annotate(分組後須要查詢的內容)
例如:

#查詢全部做者所寫書籍的總數/平均價格/總和
res = Book.objects.all().values("authors__name").annotate(Avg("price"),Count("price"),Sum("price"))
# print('res==',res)
# 查詢全部做者所寫書籍中價格大於50元的總數/平均價格/總和
res = Book.objects.filter(price__gt = 50).values("authors__name").annotate(Avg("price"), Count("price"), Sum("price"))
# print('res==', res)

#查詢各個出版社最便宜書的價格
#錯誤寫法:若是以book進行查詢,則查詢的結果會以書爲主體,則當出版社未出版書時結果不顯示出來(由於是以書爲主體,而不是以出版社爲主體的)
res = Book.objects.all().values("publish__name").annotate(Min("price"))
print("res=",res)
print('---'*20)
#正確寫法,以publish爲主體進行分組查詢
res = Publish.objects.all().values('name').annotate(minprice = Min("book__price"))  #minprice自定義別名
print("res=", res)

Django5_model模型
八.F查詢和Q查詢
當咱們須要把全部書籍的價格提升10元時,又該怎麼操做呢?在sql中應該爲:update book set price = (price+10)
Django5_model模型
此時咱們能夠考慮使用django中的F()函數 
做用:操做數據表中的某列值,F()容許Django在未實際連接數據的狀況下具備對數據庫字段的值的引用,不用獲取對象放在內存中再對字段進行操做,直接執行原生產sql語句操做。一般狀況下咱們在更新數據時須要先從數據庫裏將原數據取出後方在內存裏,而後編輯某些屬性,最後提交。

#修改全部書籍的價格使其加價10元
Book.objects.all().update(price=F("price")+10)

Django5_model模型
在上面的全部場景中,咱們在進行查詢時的過濾條件(filter()函數))只使用了單條件或者多條件(and)查詢,沒法使用or 或者not進行查詢。此時django提供了Q()函數來完成or 或 not功能。
做用:對對象進行復雜查詢,並支持&(and),|(or),~(not)操做符。

#Q查詢和關鍵字查詢並用,注意此時必須Q()放在關鍵字前面,不然報錯
#查詢全部南方出版社出版且價格大於50的書籍
book1 = Book.objects.filter(Q(publish__name='南方出版社'),price__lt=50)
print("book1=",book1)
book2 = Book.objects.filter(price__lt=50,publish__name='南方出版社')
print('book2=',book2)

Django5_model模型

# 查詢全部南方出版社出版或者價格大於100的書籍
book3 = Book.objects.filter(Q(publish__name='南方出版社')| Q(price__gt=100)).values("title")

Django5_model模型

# 查詢全部南方出版社出版或者價格不大於100的書籍
book4 = Book.objects.filter(Q(publish__name='南方出版社')|Q(price__lte=100)).values("title")
print('book4=', book4)
book5 = Book.objects.filter(Q(publish__name='南方出版社') | ~Q(price__gt=100)).values("title")
print('book5=', book5)

Django5_model模型
九.QuerySet集合對象的特殊屬性
1.不使用QuerySet時不進行查詢數據庫操做
Django5_model模型
2.同一個QuerySet,django有緩存不會重複操做數據庫,直接讀取緩存;若是中間修改了後面須要使用則應該從新查詢獲取QuerySet
Django5_model模型
Django5_model模型
Django5_model模型
QuerySet的特性:
1.可切片
2.可迭代性
可迭代性說明:django的QuerySet自帶cache機制(緩存機制),它會把一次性查出的結果都放進緩存中,當數據量極大時會致使內存被極大的消耗,此時會嚴重影響性能。此時,咱們能夠考慮使用python的迭代器iterator()進行處理,這裏每次只存儲部分少許須要使用的數據在內存中,經過next()方法進行獲取下次須要的數據。這樣既能夠知足需求,又能夠節省內存。可是,使用iterator()並不會生成QuerySet緩存,可能會須要額外的查詢數據庫。exists()也是不會生成QuerySet緩存。
Django5_model模型
十.歡迎關注做者公衆號
Django5_model模型

相關文章
相關標籤/搜索