一.創建表
Django自帶數據庫ORM是基於SQLite,如果使用sqlite則不需要做配置修改,如果需要基於mysql連接則需要做相關配置:
1.在安裝好的mysql中創建數據庫,注意字符集選擇utf8以便支持漢字(ORM不支持創建數據庫,只能創建表)
2.在創建的Django項目同名文件夾中 setting.py 配置對於mysql數據庫的連接:
1 # 1.將默認的設置注釋掉: 2 # DATABASES = { 3 # 'default': { 4 # 'ENGINE': 'django.db.backends.sqlite3', 5 # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 6 # } 7 # } 8 9 # 2.設置對於mysql的連接: 10 DATABASES = { 11 'default': { 12 'ENGINE': 'django.db.backends.mysql', 13 'NAME':'new', #數據庫名稱 14 'USER': 'root', #用戶名 15 'PASSWORD': 'pwd', #密碼 16 'HOST': 'localhost', #連接地址,可以不填 17 'PORT': 3306, #端口 18 } 19 }
3.在同層目錄下的__init__.py文件導入對應模塊:
import pymysql
pymysql.install_as_MySQLdb()
此時基本配置已經完成,接下來進入處理業務代碼的app01文件夾下的models.py中進行對ORM的建表操作
1 from django.db import models #導入django ORM對應模塊 2 3 # Create your models here. 4 class Class1(models.Model): #繼承models模塊定制類,即創建表,類名為表明 5 cid = models.AutoField(primary_key=True) #創建主鍵,AutoField為自增(主鍵可以不寫,不寫時默認生成一行名稱為ID的主鍵列) 6 cname = models.CharField(max_length=32) #創建char類型字符串,最大長度32 7 8 class Teacher(models.Model): 9 tid = models.AutoField(primary_key=True) 10 tname = models.CharField(max_length=32) 11 12 class Student(models.Model): 13 sid = models.AutoField(primary_key=True) 14 sname = models.CharField(max_length=32) 15 Class = models.ForeignKey(Class1) #創建外鍵,括號里面填寫外鍵關系的表名 這個類在生成時,Class列會顯示為Class_id即自寫的列名加_id 16 17 class Guanxi(models.Model): 18 teacher = models.ForeignKey(Teacher) 19 Class = models.ForeignKey(Class1)
當類表定制完畢時,cmd切換到Django項目的根目錄,運行命令:(注意將python添加至環境變量)
python manage.py makemigrations
python manage.py migrate
此時數據表即完成創建成功,如有報錯,注意查看某個字段是否類型錯誤,檢查之前步驟是否有遺漏。
如果是用的sqlite創建,可以用pycharm自帶的可視化以及Django的sqlite結合查看表。(將項目中的sqlite3拖拽到pycharm編輯器右上角點開的Database中)
二:基於ORM對表進行增刪改查:
本次操作在views模塊中,因此首先導入之前創建的表類
from app01 import models
1 查: 2 res = models.UserType.objects.all() #獲取表所有數據,得到一個QuerySet[obj,obj,obj],類似一個個對象組成的列表,循環列表取到的為對象,擁有表的字段屬性。 3 for row in res: 4 print(row.cid,row.cname) 5 6 res = models.UserType.objects.all() .first() #獲取表所有數據的第一行,實際為一個Obj對象,可以res.cid,res.cname取值 7 8 res = models.UserType.objects.filter(cid=1) 9 res = models.UserInfo.objects.filter(id__gt=1) id大於1 10 res = models.UserInfo.objects.filter(id__lt=1) id小於1 11 #filter查詢時,括號里面可以添加條件,得到的依然為QuerySet,需要取值依舊需要for 循環 或者后面加.first()方法,當然也可以按索引取值,得到的也是obj對象 12 13 res = models.UserInfo.objects.all().values('id','name') #實際還是QuerySet,括號里面可以限定需要查詢的列,不同的是,這里循環出來的不再是對象,而是一個個的字典 QuerySet[{'id':'xx','name':'xx'} ] 取值需按字典key取值。 14 # 跨表 __ 15 # result = models.UserInfo.objects.all().values('id','name',"ut__title") 16 # for item in result: 17 # print(item['id'],item['name'],item['ut__title']) 18 19 20 res = models.UserInfo.objects.all().values_list('id','name') #得到QuerySet[(1,'f'), ] 循環出來的還是一個個的列表,列表索引取值。 21 22 # 跨表 __ 23 # result = models.UserInfo.objects.all().values_list('id','name',"ut__title") 24 # for item in result: 25 # print(item[0],item[1],item[2]) 26 27 28 29 增: 30 #增加為create(),括號里面填寫數據行需要的各個數據即可 31 models.UserType.objects.create(title='普通用戶') 32 33 34 35 刪: 36 #刪除需在查詢到數據的基礎上,后面加上.delete()方法即可 37 models.UserInfo.objects.filter(id=1).delete() 38 39 40 改: 41 #對應的,修改也是在查詢的基礎上,加.update()方法 42 models.Student.objects.filter(sid=a1).update(sname=name,Class_id=cid) 43 44 #外鍵操作:以下操作基於2個表已經建立外鍵關系的基礎 45 ##正向操作: 46 # UserInfo,ut是FK字段 - 正向操作 PS: 一個用戶只有一個用戶類型 47 obj = models.UserInfo.objects.all().first() 48 print(obj.name,obj.age,obj.ut.title) 49 #通過.外鍵名.對應關系表的字段列名即可拿到UserType表里面的title列值 50 #同樣的如果有多個關系表連表操作時,可以一直.外鍵無窮無盡的連表取到需要的值 51 52 #反向操作: 53 # UserType, 表名小寫_set.all() - 反向操作 PS: 一個用戶類型下可以有很多用戶 54 obj = models.UserType.objects.all().first() #取到用戶類型的其中一個Obj 55 print('用戶類型',obj.id,obj.title) 56 #通過用戶類型查看該類型下有多少個用戶 57 for row in obj.userinfo_set.all(): 58 print(row.name,row.age) 59 60 61 result = models.UserType.objects.all() 62 for item in result: 63 print(item.title,item.userinfo_set.filter(name='xx'))
1 有三個表: 2 class Boy(models.Model): 3 name = models.CharField(max_length=32) 4 5 class Girl(models.Model): 6 nick = models.CharField(max_length=32) 7 8 class Love(models.Model): 9 b = models.ForeignKey('Boy',null=True) 10 g = models.ForeignKey('Girl',null=True) 11 #聯合唯一索引 12 #class Meta: 13 # unique_together = [ 14 # ('b','g'), 15 #] 16 17 1.通過Boy表中name為條件查找Girl表有關聯的nick值: 18 插數據: 19 # obj_list = [ 20 # models.Boy(name='劉德華'), 21 # models.Boy(name='張學友'), 22 # models.Boy(name='郭富城'), 23 # models.Boy(name='黎明'), 24 # ] 25 # objs = [ 26 # models.Girl(nick='陳慧琳'), 27 # models.Girl(nick='容祖兒'), 28 # models.Girl(nick='鄭秀文'), 29 # models.Girl(nick='蒙嘉慧'), 30 # ] 31 # models.Boy.objects.bulk_create(obj_list,5) 32 # models.Girl.objects.bulk_create(objs,5) 33 建立關系 34 # models.Love.objects.create(b_id=1,g_id=1) 35 # models.Love.objects.create(b_id=1,g_id=4) 36 # models.Love.objects.create(b_id=2,g_id=2) 37 # models.Love.objects.create(b_id=2,g_id=3) 38 # models.Love.objects.create(b_id=2,g_id=4) 39 多對多的關系查詢: 40 # lo_list = models.Love.objects.filter(b__name='劉德華').values('b__name','g__nick') 41 # for i in lo_list: 42 # print(i['b__name'],i['g__nick']) 43 # 44 # lov_list = models.Love.objects.filter(b__name='張學友').select_related('b','g') 45 # for row in lov_list: 46 # print(row.b.name,row.g.nick) 47 48 二。兩個表的關系也可以不再建關系表Love,通過Django內置ORM的功能同樣可以建立表之間的關系,查找時通過間接查找。 49 class Boy(models.Model): 50 name = models.CharField(max_length=32) 51 m = models.ManyToManyField('Girl') 52 53 class Girl(models.Model): 54 nick = models.CharField(max_length=32) 55 56 如此,同樣可以建立關系,只不過增刪改查相應也有變化。 57 58 obj = models.Boy.objects.filter(name='劉德華').first() #取到篩選出的Boy對象: 59 #增 60 obj.m.add(1) 61 obj.m.add(*[2,3,]) 62 63 # 刪: 64 obj.m.remove(1,) 65 obj.m.remove(*[2,]) 66 67 #改 68 obj.m.set([1,2,]) #實為重置,將之前的全部刪除重新建立關系 69 70 #查 71 q = obj.m.all() #q得到對應關系的Girl對象
三.Django之自定義分頁
由於Django自帶分頁具有局限性,且其它框架都不包含分頁功能,因此這里自定義一個分頁功能模塊。
1 # Create your views here. 2 #定制分頁類: 3 class PageInfo(object): 4 def __init__(self,current_page,all_count,per_page,base_url,show_page=11): 5 """ 6 7 :param current_page:當前頁 8 :param all_count: 數據庫總行數 9 :param per_page: 每頁顯示行數 10 :param base_url: 需要分頁的url 11 :param show_page: 頁面可以顯示的頁數 12 :return: 13 """ 14 """將傳入的當前頁轉為int 如果傳入的為字符串,拋出異常直接 15 將當前頁設置為第一頁""" 16 try: 17 self.current_page = int(current_page) 18 except Exception as e: 19 self.current_page = 1 20 21 self.per_page = per_page 22 """通過數據庫所有數據的行數除以每頁顯示的行數,得到需要一共 23 顯示的頁數,如果有余數則商要+1,余下的行單獨一頁""" 24 a,b = divmod(all_count,per_page) 25 if b: 26 a = a+1 27 self.all_pager = a 28 self.show_page = show_page 29 self.base_url = base_url 30 31 """通過當前頁碼以及頁面顯示行數來獲取頁面上顯示的具體行的數據 32 如第1頁就是1-10行,第2頁為11-20行,""" 33 def start(self): 34 return (self.current_page-1) * self.per_page 35 def end(self): 36 return self.current_page * self.per_page 37 38 """實際執行函數""" 39 def pager(self): 40 41 page_list = [] 42 #如果頁面上顯示11頁,樣式應該是當前頁前面一半后面一半,所以-1然后/2 43 half = int((self.show_page-1)/2) 44 # 如果數據總頁數<11 show_page,即不足11頁,就只顯示數據一共能顯示的頁數 45 if self.all_pager < self.show_page: 46 begin = 1 47 stop = self.all_pager 48 # :param begin:當前頁面顯示的最左頁,即第一頁 49 # :param stop: 當前顯示的最右,即最后一頁 50 else: 51 # 如果當前頁 <=5,永遠顯示1,11 52 if self.current_page <= half: 53 begin = 1 54 stop =self.show_page 55 else: 56 # 如果當前頁+5 大於實際存在的最大頁,比如一共有35頁,當前頁為 57 # 32,再取后5頁就是37,則36、37為空,所以加個判定,超過極限就 58 # 取最右頁為實際最大頁,最左就是-11,即還是一共顯示11頁, 59 if self.current_page + half > self.all_pager: 60 begin = self.all_pager - self.show_page + 1 61 stop = self.all_pager 62 else: 63 #這里為正常情況,顯示當前頁的前5頁跟后5頁 64 begin = self.current_page-half 65 stop = self.current_page + half 66 67 #上一頁功能 68 #當前頁小於等於1,上一頁沒有內容 69 if self.current_page <= 1: 70 prev = "<li><a href='#'>上一頁</a></li>" 71 #拼接字符串生成li a標簽 上一頁頁數為當前頁-1,添加到列表中 72 else: 73 prev = "<li><a href='%s?page=%s'>上一頁</a></li>" %(self.base_url,self.current_page-1,) 74 page_list.append(prev) 75 76 #當前頁面同時顯示的頁面,由上面賦值的最左與最右頁決定,+1是因為for循環range不顧尾 77 for i in range(begin,stop+1): 78 if i == self.current_page: 79 # 當前頁給一個class,CSS顯示效果區別於其它頁 80 temp = "<li class='active'><a href='%s?page=%s'>%s</a></li>" % (self.base_url, i, i,) 81 else: 82 temp = "<li><a href='%s?page=%s'>%s</a></li>" % (self.base_url, i, i,) 83 page_list.append(temp) 84 85 #下一頁功能,同樣的當前頁>=最大頁一樣不跳轉 86 if self.current_page >= self.all_pager: 87 nex = "<li><a href='#'>下一頁</a></li>" 88 else: 89 nex = "<li><a href='%s?page=%s'>下一頁</a></li>" % (self.base_url, self.current_page + 1,) 90 page_list.append(nex) 91 #此時列表中按順序含有上一頁的li a標簽,需要顯示的11頁li a標簽,以及下一頁標簽 92 #拼接成字符串並作為函數的返回值以供調用接收 93 return ''.join(page_list)
