首先要說的是django與其他的框架不同,django是一個封裝的及其完善的框架,我們使用django也不會像之前寫學生系統那樣,django操作資料庫使用自帶的ORM來進行操作,Torando與Flask的資料庫使用就很自由(當然也可以使用我們之前的SQL helper),並且Flask的模板都不 ...
首先要說的是django與其他的框架不同,django是一個封裝的及其完善的框架,我們使用django也不會像之前寫學生系統那樣,django操作資料庫使用自帶的ORM來進行操作,Torando與Flask的資料庫使用就很自由(當然也可以使用我們之前的SQL helper),並且Flask的模板都不是自帶的而是使用的第三方插件。
首先創建一個工程:
django-admin startproject mysite
創建一個應用:
python manage.py starapp app01
每一個新建的app下都有幾個文件:
migrations文件夾,存放資料庫的相關信息;
admin.py文件,Django自帶後臺管理相關配置;
modals.py,ORM的相關操作;
tests.py,單元測試;
views文件夾或者文件,業務處理。
路由系統
之前的學生系統傳遞nid都是通過url進行傳遞,這樣導致鏈接的seo權重比較低,所以我們可以進行簡單的優化。
動態路由:當一條url被路由url(r'^edit/(\w+)/', views.edit)匹配到,那麼在視圖函數中定義的函數就要傳入額外的參數來盛放被正則匹配到的值。
#url url(r'^edit/(\w+)/(\w+)/', views.edit) #視圖函數 def edit(request,a1,a2): print(a1) print(a2) return HttpResponse('...')
上面的例子是順序傳參,當然也可以指定傳參,
#指定傳參 url(r'^edit/(?P<a2>\w+)/(?P<a1>\w+)/', views.edit)
#視圖函數
def edit(request,a2,a1):
print(a1)
print(a2)
return HttpResponse('...')
註:這兩種傳參方式不可以混著用,與函數傳參不同的是此處的傳參不可以用*args和**kwargs接收。
偽靜態:
終止符: ^edit$ 偽靜態: url(r'^edit/(\w+).html$', views.edit),
路由分發
為了防止不同業務線(app)的開發過程中出現的名稱重覆,所以才有了路由分發的必要性。
from django.conf.urls import url,include urlpatterns = [ url(r'^app01/', include('app01.urls')),]
這樣路由進來就被分發到app01裡面的urls進行進一步路由匹配。
別名與反向生成url
url(r'^edit/(\w+)/(\w+)/', views.edit,name='n2') #name就是別名 #在視圖函數中: from django.urls import reverse v = reverse('n2',args=(1111,)) #url要是指定傳參,reverse里就要用kwargs存放字典指定返回值。
反生成url可應用在html頁面中,
#url(r'^login/', views.login,name='m1'), # def login(request): # return render(request,'login.html') #login.html <form method="POST" action="{% url "m1" %}"> <input />
這裡的{% url "m1" %}會被渲染成能被^login/匹配的地址。
url(r'^edit/(\w+)/', views.edit,name='n2'),
{% url "n2" i %}與/edit/{{ i }}/一樣,這裡n2先被替換成正則前半部分,後面匹配的部分由i傳參進去。
ORM框架
ORM一般用來做原生資料庫語句轉換,使我們開發更為高效。ORM不僅可以進行數據行的增刪改查操作,還可以創建,修改,刪除數據表(所以功能很強大,可以完成大部分的資料庫操作)。
註:python沒有辦法創建資料庫,只能是連接資料庫。
ORM利用pymysql等第三方工具連接資料庫(不能直接鏈接資料庫,並且預設不是連接MySQL而是SQLlite)。而且預設鏈接MySQL的是MySQLDB模塊。python3預設沒裝MySQLDB模塊,所以最方便就是更改它預設連接MySQL的配置。
#預設 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } #連接MySQL DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'dbname', 'USER': 'root', 'PASSWORD': 'xxx', 'HOST': '', 'PORT': '', } }
最後,我們還需要更改project下麵的init,
import pymysql pymysql.install_as_MySQLdb()
這樣我們就可以使用ORM操作pymysql連接MySQL資料庫了。
models文件中創建數據表的各項屬性:
from django.db import models class UserInfo(models.Model):#必須繼承 """ 員工 """ nid = models.BigAutoField(primary_key=True)#自增可不寫 user = models.CharField(max_length=32) password = models.CharField(max_length=64)#位數也很重要 age = models.IntegerField(default=1)
接著要在INSTALLED_APPS[]裡加入我們註冊的app名。
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'mysite', ]INSTALLED_APPS
最後一步,在終端輸入
python manage.py makemigrations
python manage.py migrate
再去查看資料庫就會增加很多表,其中app01_userinfo才是我們剛纔創建的那張表。
這兩行操作就是在app下migrations生成配置文件相關操作,migrate拿著配置信息去資料庫進行相關操作。
以後我們要是修改表的名字就直接修改類,然後再次在終端執行這兩條命令即可,當然比如要增加一行數據(例如UserInfo表裡的最後一行age),如果之前有數據,之前的數據可沒有age參數,那該怎麼辦呢,要麼把這行數據設置為null允許為空,要麼就設置預設值。
外鍵創建
class UserGroup(models.Model): """ 部門 """ title = models.CharField(max_length=32) class UserInfo(models.Model): """ 員工 """ nid = models.BigAutoField(primary_key=True) user = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField(default=1) # ug_id ug = models.ForeignKey("UserGroup",null=True)
ug = models.ForeignKey("UserGroup",null=True)預設在資料庫中多出來的數據是ug_id。
ORM的增刪改查
增
models.UserGroup.objects.create(title='銷售部')
查
group_list = models.UserGroup.objects.all()#所有 group_list = models.UserGroup.objects.filter(id=1)#過濾 group_list = models.UserGroup.objects.filter(id__gt=1)#神奇的雙下劃線
刪
models.UserGroup.objects.filter(id=2).delete()
更新
models.UserGroup.objects.filter(id=2).update(title='公關部')
# 資料庫相關操作 def index(request): # 增刪改查 from app01 import models # 新增 # models.UserGroup.objects.create(title='銷售部') # models.UserInfo.objects.create(user='root',password='pwd',age=18,ug_id=1) # 查找 # group_list = models.UserGroup.objects.all() # group_list = models.UserGroup.objects.filter(id=1) # group_list = models.UserGroup.objects.filter(id__gt=1) # group_list = models.UserGroup.objects.filter(id__lt=1) # 刪除 # models.UserGroup.objects.filter(id=2).delete() # 更新 models.UserGroup.objects.filter(id=2).update(title='公關部') # group_list QuerySet類型(列表) # QuerySet類型[obj,obj,obj] # print(group_list) # for row in group_list: # print(row.id,row.title) # models.UserInfo.objects.all() group_list = models.UserGroup.objects.all() return render(request,'newindex.html',{"group_list": group_list})Views.py
這裡我們查找的group_list是形似列表的QuerySet類型。QuerySet類型可以理解為[obj,obj,obj]。
for row in group_list: print(row.id,row.title)
同理在前端一樣適用
{% for row in group_list %} <li>{{ row.id }} === {{ row.title }}</li> {% endfor %}
ORM之連表操作
我們之前的兩張表,通過外鍵連接,其中ut直接連接UserType,ut代指了usertype的一行數據,我們可以直接使用ut.title直接跨表查詢。
from django.db import models class UserType(models.Model): """ 用戶類型 """ title = models.CharField(max_length=32) class UserInfo(models.Model):#必須繼承 """ 員工 """ id = models.BigAutoField(primary_key=True)#自增可不寫 name = models.CharField(max_length=32) age = models.IntegerField(default=1) # ug_id ut = models.ForeignKey("UserType",null=True)#外鍵操作 #創建用戶數據 from app01 import models def test(request): # 創建數據 # models.UserType.objects.create(title='普通用戶') # models.UserType.objects.create(title='二逼用戶') # models.UserType.objects.create(title='牛逼用戶') #不要重覆添加 # models.UserInfo.objects.create(name='方',age=18,ut_id=1) # models.UserInfo.objects.create(name='由',age=18,ut_id=2) # models.UserInfo.objects.create(name='劉',age=18,ut_id=2) # models.UserInfo.objects.create(name='陳',age=18,ut_id=3) # models.UserInfo.objects.create(name='王',age=18,ut_id=3) # models.UserInfo.objects.create(name='楊',age=18,ut_id=1) return HttpResponse('...')創建數據表的數據
# 獲取 # result取到的是QuerySet[obj,obj,obj] result = models.UserInfo.objects.all() for obj in result: print(obj.name,obj.age,obj.ut_id,obj.ut.title)#直接就連表取到值直接跨表
# UserInfo,ut是FK欄位 - 正向操作 PS: 一個用戶只有一個用戶類型 obj = models.UserInfo.objects.all().first()#取出第一個queryset數據 print(obj.name,obj.age,obj.ut.title)#因為obj只是一個數據只能對應一種用戶正向跨表
# UserType, 表名小寫_set.all() - 反向操作 PS: 一個用戶類型下可以有很多用戶 obj = models.UserType.objects.all().first() print('用戶類型',obj.id,obj.title) for row in obj.userinfo_set.all():#obj.userinfo_set里是userinfo的query對象,.all()取出所有數據 print(row.name,row.age)反向跨表
#反向取出每一行的queryset result = models.UserType.objects.all() for item in result:#相當於取出每一行用戶類型對應的用戶的queryset for i in item.userinfo_set.all(): print(i.name) #過濾每一行 result = models.UserType.objects.all().filter(id= 1 )#<QuerySet [<UserType: UserType object>]> for item in result: print(item.userinfo_set.filter(id =1))#<QuerySet [<UserInfo: UserInfo object>]>反向跨表補充
result = models.UserInfo.objects.all().values('id','name')#只取兩列 # 並且每列的QuerySet[{'id':'xx','name':'xx'} ]都是這樣的字典 for row in result: print(row) result2 = models.UserInfo.objects.all().first() print(result2)#UserInfo object字典取值
result = models.UserInfo.objects.all().values_list('id','name') # QuerySet[(1,'f'), ] for row in result: print(row)元組取值
當取出的queryset裡面是obj對象的時候,可以直接在for迴圈里跨表,但是當取出的queryset里是字典或者元祖對象的時候,那麼在for迴圈里就不可以跨表了,這時候就要使用神奇的雙下劃線 models.UserInfo.objects.filter(id__gt=1).values('id','name')#可以取到id>1的queryset對象。 # [{id:1,name:fd},{id:1,name:fd},{id:1,name:fd},] # models.UserInfo.objects.all().values('id','name') # models.UserInfo.objects.filter(id__gt=1).values('id','name') # 無法跨表 # result = models.UserInfo.objects.all().values('id','name') # for item in result: # print(item['id'],item['name']) # 誇表 __ # result = models.UserInfo.objects.all().values('id','name',"ut__title") # for item in result: # print(item['id'],item['name'],item['ut__title']) # [(1,df),(2,'df')] # models.UserInfo.objects.all().values_list('id','name') # models.UserInfo.objects.filter(id__gt=1).values_list('id','name') # 無法跨表 # result = models.UserInfo.objects.all().values_list('id','name') # for item in result: # print(item[0],item[1]) # 誇表 __ # result = models.UserInfo.objects.all().values_list('id','name',"ut__title") # for item in result: # print(item[0],item[1],item[2])神奇的雙下劃線
v = models.UserInfo.objects.values('id','name') # 6 v = models.UserInfo.objects.values('id','name','ut__title') # 6 # select * from userinfo left join usertype v1 = models.UserType.objects.values('id','title') print(v1) # 4 v2 = models.UserType.objects.values('id','title','userinfo__name') print(v2) #7 # select * from usertype left join userinfo #正向跨表與反向跨表與left join類似,誰在前面就是查他的所有,沒有匹配到的那一行值為none填充 正: 1. q = UserInfo.objects.all().first() q.ug.title 2. UserInfo.objects.values('nid','ug_id') UserInfo.objects.values('nid','ug_id','ug__title') 3. UserInfo.objects.values_list('nid','ug_id','ug__title') 反: 1. 小寫的表名_set obj = UserGroup.objects.all().first() result = obj.userinfo_set.all() [userinfo對象,userinfo對象,] 2. 小寫的表名 v = UserGroup.objects.values('id','title') v = UserGroup.objects.values('id','title','小寫的表名稱') v = UserGroup.objects.values('id','title','小寫的表名稱__age') 3. 小寫的表名 v = UserGroup.objects.values_list('id','title') v = UserGroup.objects.values_list('id','title','小寫的表名稱') v = UserGroup.objects.values_list('id','title','小寫的表名稱__age')
正向:
xxxx.filter(ut__title='超級用戶').values('id','name','ut__title')
反向:
xxxx.filter(表名稱__title='超級用戶').values('id','name','表名稱__title')
# 1.增刪改查 # 2. 一般: # models.UserInfo.objects.filter(id__gt=1) # models.UserInfo.objects.filter(id__lt=1) # models.UserInfo.objects.filter(id__lte=1) # models.UserInfo.objects.filter(id__gte=1) # models.UserInfo.objects.filter(id__in=[1,2,3]) # models.UserInfo.objects.filter(id__range=[1,2]) # models.UserInfo.objects.filter(name__startswith='xxxx') # models.UserInfo.objects.filter(name__contains='xxxx') # models.UserInfo.objects.exclude(id=1) # 3. 排序 user_list = models.UserInfo.objects.all().order_by('-id','name') # 4. 分組 from django.db.models import Count,Sum,Max,Min # v =models.UserInfo.objects.values('ut_id').annotate(xxxx=Count('id')) # print(v.query) # v =models.UserInfo.objects.values('ut_id').annotate(xxxx=Count('id')).filter(xxxx__gt=2) # print(v.query)having # v =models.UserInfo.objects.filter(id__gt=2).values('ut_id').annotate(xxxx=Count('id')).filter(xxxx__gt=2) # print(v.query)where # 5. F,更新時用於獲取原來的值 # from django.db.models import F,Q # models.UserInfo.objects.all().update(age=F("age")+1) # 6. Q,用於構造複雜查詢條件 # 應用一: # models.UserInfo.objects.filter(Q(id__gt=1)) # models.UserInfo.objects.filter(Q(id=8) | Q(id=2)) # models.UserInfo.objects.filter(Q(id=8) & Q(id=2)) # 應用二: # q1 = Q() # q1.connector = 'OR' # q1.children.append(('id__gt', 1)) # q1.children.append(('id', 10)) # q1.children.append(('id', 9)) # # # q2 = Q() # q2.connector = 'OR' # q2.children.append(('c1', 1)) # q2.children.append(('c1', 10)) # q2.children.append(('c1', 9)) # # q3 = Q() # q3.connector = 'AND' # q3.children.append(('id', 1)) # q3.children.append(('id', 2)) # q2.add(q3,'OR') # # con = Q() # con.add(q1, 'AND') # con.add(q2, 'AND') # (id=1 or id = 10 or id=9 or (id=1 and id=2)) and (c1=1 or c1=10 or c1=9) # models.UserInfo.objects.filter(con) # condition_dict = { # 'k1':[1,2,3,4], # 'k2':[1,], # } # con = Q() # for k,v in condition_dict.items(): # q = Q() # q.connector = 'OR' # for i in v: # q.children.append(('id', i)) # con.add(q,'AND') # models.UserInfo.objects.filter(con) # 7. extra, 額外查詢條件以及相關表,排序 models.UserInfo.objects.filter(id__gt=1) models.UserInfo.objects.all() # id name age ut_id models.UserInfo.objects.extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # a. 映射 # select # select_params=None # select 此處 from 表 # b. 條件 # where=None # params=None, # select * from 表 where 此處 # c. 表 # tables # select * from 表,此處 # c. 排序 # order_by=None # select * from 表 order by 此處 models.UserInfo.objects.extra( select={'newid':'select count(1) from app01_usertype where id>%s'}, select_params=[1,], where = ['age>%s'], params=[18,], order_by=['-age'], tables=['app01_usertype'] ) """ select app01_userinfo.id, (select count(1) from app01_usertype where id>1) as newid from app01_userinfo,app01_usertype where app01_userinfo.age > 18 order by app01_userinfo.age desc """ result = models.UserInfo.objects.filter(id__gt=1).extra( where=['app01_userinfo.id < %s'], params=[100,], tables=['app01_usertype'], order_by=['-app01_userinfo.id'], select={'uid':1,'sw':"select count(1) from app01_userinfo"} ) print(result.query) # SELECT (1) AS "uid", (select count(1) from app01_userinfo) AS "sw", "app01_userinfo"."id", "app01_userinfo"."name", "app01_userinfo"."age", "app01_userinfo"."ut_id" FROM "app01_userinfo" , "app01_usertype" WHERE ("app01_userinfo"."id" > 1 AND (app01_userinfo.id < 100)) ORDER BY ("app01_userinfo".id) DESC # 8. 原生SQL語句 from django.db import connection, connections cursor = connection.cursor() # connection=default數據 cursor = connections['db2'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() row = cursor.fetchall() - extra - 原生SQL語句 - raw result = models.UserInfo.objects.raw('select * from userinfo') [obj(UserInfo),obj,] result = models.UserInfo.objects.raw('select id,1 as name,2 as age,4 as ut_id from usertype') [obj(UserInfo),obj,] v1 = models.UserInfo.objects.raw('SELECT id,title FROM app01_usertype',translations=name_map) # 9. 簡單的操作 http://www.cnblogs.com/wupeiqi/articles/6216618.htmlDjango ORM操作
# """ # select # id, # name, # (select count(1) from tb) as n # from xb where .... # """ # # v = models.UserInfo.objects.all().extra( # select={ # 'n':"select count(1) from app01_usertype where id=%s or id=%s", # 'm':"select count(1) from app01_usertype where id=%s or id=%s", # }, # select_params=[1,2,3,4]) # for obj in v: # print(obj.name,obj.id,obj.n) # models.UserInfo.objects.extra( # where=["id=1","name='alex'"] # ) # models.UserInfo.objects.extra( # where=["id=1 or id=%s ","name=%s"], # params=[1,"alex"] # ) # models.UserInfo.objects.extra( # tables=['app01_usertype'], # ) # """select * from app01_userinfo,app01_usertype""" # result = models.UserInfo.objects.filter(id__gt=1) # print(result.query) # result = models.UserInfo.objects.filter(id__gt=1).extra( # where=['app01_userinfo.id < %s'], # params=[100,], # tables=['app01_usertype'], # order_by=['-app01_userinfo.id'], # select={'uid':1,'sw':"select count(1) from app01_userinfo"} # ) # print(result.query) # v = models.UserInfo.objects.all().order_by('-id','name') # v = models.UserInfo.objects.all().order_by('-id','name').reverse()#只有加order by才可以用reverse # v = models.UserInfo.objects.all().order_by('id','-name') # print(v) # v = models.UserInfo.objects.all() # [obj] # v = models.UserInfo.objects.all().only('id','name')#只拿id,only,還是obj,能取到age但是不要用only還去取,因為每次取都增加一次查詢 # v = models.UserInfo.objects.all().defer('name')#除了name以外的數據 # # [obj] # for obj in v: # obj.id,obj.name # models.UserInfo.objects.values('id','name') # [{id,nam}] # models.UserInfo.objects.all().using('db2')#指定去哪個資料庫取 # models.UserInfo.objects.all().filter().all().exclude().only().defer() # models.UserInfo.objects.none() # result = models.UserInfo.objects.aggregate(k=Count('ut_id', distinct=True), n=Count('id')) # print(result) # v = models.UserInfo.objects.all().first() # # models.UserInfo.objects.get(id=1) # # obj = models.UserType.objects.create(title='xxx') # obj = models.UserType.objects.create(**{'title': 'xxx'}) # print(obj.id) # # obj = models.UserType(title='xxx') # obj.save() # objs = [ # models.UserInfo(name='r11'), # ] # models.UserIn