Django框架 pip3 install django 命令: # 建立Django程序 django-admin startproject mysite # 進入程序目錄 cd mysite # 啓動socket服務端,等待用戶發送請求 python manage.py runserver 127.0.0.1:8080 # 建立app python manage.py starapp app01 pycharm 1. 建立project 2. 配置: - 模板路徑 template目錄 TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'template')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ],},},] - 靜態文件路徑 static目錄 STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), ) 3. 額外配置 MIDDLEWARE = [#'django.middleware.csrf.CsrfViewMiddleware',]
瀏覽器(socket客戶端) 2. 發送IP和端口 http://www.baidu.com:80/index/ GET: 請求頭 http1.1 /index?p=123 請求體(無內容) POST: 請求頭 http1.1 /index?p=123 請求體 ... 4. 接收響應 普通響應:頁面直接顯示 重定向響應:再一塊兒一次Http請求 服務器(socket服務端) 1. 啓動並監聽ip和端口,等待用戶鏈接 3. 接收請求進行處理,並返回 普通返回: 響應頭: Access-Control-Allow-Origin:* 響應體: <html>...</html> 重定向返回: 響應頭: LOCATION: 'http://www.baidu.com' Access-Control-Allow-Origin:*
urls.py from django.urls import path,re_path from app01 import views urlpatterns = [ # path('admin/', admin.site.urls), path('index/', views.index), re_path('^edit/(\w+)/$',views.edit1), # 加上 $ re_path('^edit/(\w+).html$',views.edit2), re_path('^edit/(?P<a2>\w+)/(?P<a1>\w+).html$',views.edit3), # 按參數名傳參 # def edit3(request,*args,**kwargs): # 不要將(\w+)與(?P<a2>\w+)混用 # 若是前面不加結尾符,則不能匹配此url path('index2/', views.index2,name='n2'), # 給url命名;在函數中經過別名反找到url re_path('index3/(\w+)', views.index3,name='n3'), # 可隨意生成(\w+)位置的值 re_path('^index4/(?P<a2>\w+)/(?P<a1>\w+).html$', views.index4,name='n4'), # 可隨意生成(?P<a2>\w+)位置的值 re_path('^', default), # 此規則放最後 # 什麼都不輸或者輸錯了,將會被匹配 # def default(request):return HttpResponse('url 錯誤') ] views.py def edit(request,a1): # a1 爲re_path('^edit/(\w+)/$')括號中的字符,按位置傳參, # 若url中有2個括號,函數就有request參數和另2個參數 return HttpResponse('...') # 經過別名反找到url,反生成url from django.urls import reverse def index2(request): v = reverse('n2') return HttpResponse(v) def index3(request,*args): v = reverse('n3',args=(123,)) # 請求url:index3/3 生成url:index3/123 # 有多少(\w+),args=(,)就寫多少個參數 return HttpResponse(v) def index4(request,**kwargs): v = reverse('n4',kwargs={'a2':666,'a1':777)) # /index4/666/777.html # 請求url:index3/3 生成url:index3/123 # 有多少(?P<a2>\w+),kwargs={,}就寫多少個鍵值對 return HttpResponse(v) # 如果給url命名,在templates模板中能夠直接使用名字{% url 'm1' %} # path('index10/', views.index10,name='m1'), # <form method="post" action="{% url 'm1' %}"> # -><form method="post" action="/index10/"> # re_path('index10/(\w+)/', views.index10,name='m2'), # <form method="post" action="{% url 'm3' 'abc' %}"> # "補位"
路由分發: urls.py分配url到app from django.urls import path,re_path,include urlpatterns = [ path('app02/', include('app02.urls')), path('app01/', include('app01.urls')), # 只匹配開頭,而後交與app01中的urls繼續匹配 # 請求url爲 http://127.0.0.1:8000/app01/index/ # -> 先匹配到app01 -> app01下的urls中匹配index ] 在app01.urls.py文件下匹配url from django.urls import path,re_path from app01 import views urlpatterns = [ path('index/', views.index), ]
ORM操做 (Django2.1.8) Http請求: url -> 視圖(模板+數據) 步驟: 1. 建立數據庫 2. DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'s4day70db', 'USER': 'root', 'PASSWORD': '', 'HOST': 'localhost', 'PORT': 3306, } } 3. __init__文件中 import pymysql pymysql.install_as_MySQLdb() 4.註冊app INSTALLED_APPS = [app01,] 5. from django.db import models 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 = models.ForeignKey('UserGroup',on_delete=models.CASCADE,null=True) # 聯合惟一 class Meta: unique_together = [ ('b','g'),] 6.建立數據表,命令: python manage.py makemigrations python manage.py migrate # 報錯django.db.utils.InternalError: (1366, "Incorrect string value: '\\xE8\\x8B\\xB1\\xE8\\xAF\\xAD...' for column 'name' at row 1") # 解決方法,數據庫設置默認編碼 default charset=utf8 # orm中,若不手動建立models.AutoField(primary_key=True),則自動建立id列。 # 已經建立好的數據庫表,修改後從新在終端執行命令便可修改。 # 在已有列的表中增長列,設置值爲空null=True,或者default=''設置默認值。 外鍵: UserInfo表中生成外鍵,列名爲 ug_id ug(對象) 表明UserGroup中的一行數據 增 models.UserGroup.objects.create(title='銷售部') obj = models.UserGroup.objects.create(title='銷售部') print(obj.id) # 返回建立好的數據 obj = models.UserGroup(title='xxx') obj.save() # 批量插入數據 objs = [ models.UserGroup(name='name-1'), models.UserGroup(name='name-2'), ] models.UserGroup.objects.bulk_create(objs,10) 查 # 類->數據庫表,對象->數據錶行 group_list = models.UserGroup.objects.all() # 獲取全部數據 # for row in group_list: # print(row.id,row.title) group_list = models.UserGroup.objects.filter(id__gt=1) # filter(篩選條件) QuerySet[obj,obj] group_list = models.UserGroup.objects.filter(id__gt=1).first() # 取第一個值,obj對象 obj = models.UserInfo.objects.filter(id__gt=1).first() obj.ug.title # 含外鍵表查尋,對象.外鍵表列名 便可獲取主表的值。 models.UserGroup.objects.all().values('id','title') # 字典類型,兩列。 models.UserGroup.objects.all().values_list('id','title') # 元組類型,兩列。 obj = models.UserGroup.objects.filter(id__gt=1).first() obj.userinfo_set.all() # obj.userinfo_set.filter(nid=2)對另外一張表的列作篩選 # 反向操做,獲取已被關聯外鍵項的全部與之關聯的數據!? # obj.表名小寫_set.all() for row in obj.userinfo_set.all(): # 獲取到的是userinfo 中的數據 print(row.age,row.user) models.UserGroup.objects.all().values('id','title','userinfo__age') # 反向查找,跨表 models.UserInfo.objects.all().values('nid','ug__title',) # 正向查時跨表 models.UserInfo.objects.all().values_list('nid','ug__title',) # 正向查時跨表 # xxx.filter() 也能夠跨表,跟value同樣。 # 查詢主動作連表 models.UserInfo.objects.all().select_related('ug') # 不作連表,作屢次查詢 models.UserInfo.objects.all().prefetch_related('ug') user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()] # 分頁,獲取某段數據 # 排序 models.UserInfo.objects.order_by('nid') # 從大到小 models.UserInfo.objects.order_by('-nid','name') # 從小到大,id重複按name排序 # 分組 from django.db.models import Count,Sum,Min user_list = models.UserInfo.objects.values('ug_id').annotate(xxx = Count('nif')) # print(user_list,user_list.query) # <QuerySet [{'xxx': 10, 'ug_id': 1}]> SELECT `app01_userinfo`.`ug_id`, COUNT # (`app01_userinfo`.`nid`) AS `xxx` FROM `app01_userinfo` GROUP BY # `app01_userinfo`.`ug_id` ORDER BY NULL # user_list = models.UserInfo.objects.values('ug_id').annotate(xxx = Count('nid')).filter(xxx__gt=3) # 分組後篩選 # <QuerySet [{'xxx': 10, 'ug_id': 1}]> SELECT `app01_userinfo`.`ug_id`, COUNT # (`app01_userinfo`.`nid`) AS `xxx` FROM `app01_userinfo` GROUP BY # `app01_userinfo`.`ug_id` HAVING COUNT(`app01_userinfo`.`nid`) > 3 ORDER BY NULL # 其它 models.UserInfo.objects.filter(id__lt=1) # < models.UserInfo.objects.filter(id__gte=1) # >= models.UserInfo.objects.filter(id__in=[1,2,3]) # in[1,2,3,] models.UserInfo.objects.filter(id__range=[1,3]) models.UserInfo.objects.filter(id=1) models.UserInfo.objects.exclude(id=1) # id !=1 # Q # 方式一 models.UserInfo.objects.filter(Q(nid=8) | Q(nid__gt=10) & Q(caption='root')) # 方式二 組合查詢 q1 = Q() q1.connector = 'OR' q1.children.append(('id', 1)) q1.children.append(('id', 9)) q2 = Q() q2.connector = 'OR' q2.children.append(('c1', 1)) q2.children.append(('c1', 10)) con = Q() con.add(q1, 'AND') con.add(q2, 'AND') models.Tb1.objects.filter(con) # extra # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) 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 # 執行原生SQL from django.db import connection, connections cursor = connection.cursor() # cursor = connections['指定數據庫'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() - 原生SQL語句 - raw result = models.UserInfo.objects.raw('select * from userinfo') 刪 models.UserGroup.objects.filter(id=2).delete() # 注意有外鍵的狀況 更新 models.UserGroup.objects.filter(id=2).update(title='公關部') from django.db.models import F # F 用來獲取原來的值 models.UserInfo.objects.all().update(age = F('age') +1) 反向:別名,不用小寫表名作反向操做,而是用別名.all()取數據。 related_name = 'xxx' user_set ==> xxx related_query_name = 'xxx' user_set ==> xxx_set
path('login.html',views.Login.as_view()), from django.views import View class Login(View): def get(self,request): return HttpResponse('Login.get')
xss攻擊 - 慎用 safe和mark_safe 前端:{{ item|safe }} 後端:from django.utils.safestring import mark_safe tag = mark_safe(tag) - 非要用,必定要過濾關鍵字 CSRF a. 基本應用 form表單中添加 {% csrf_token %} b. 全站禁用 # 'django.middleware.csrf.CsrfViewMiddleware', c. 局部禁用 'django.middleware.csrf.CsrfViewMiddleware', from django.views.decorators.csrf import csrf_exempt @csrf_exempt def csrf1(request): if request.method == 'GET': return render(request,'csrf1.html') else: return HttpResponse('ok') d. 局部使用 # 'django.middleware.csrf.CsrfViewMiddleware', from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_protect def csrf1(request): if request.method == 'GET': return render(request,'csrf1.html') else: return HttpResponse('ok') c. 特殊CBV from django.views import View from django.utils.decorators import method_decorator @method_decorator(csrf_protect,name='dispatch') class Foo(View): def get(self,request): pass def post(self,request): pass
def wrapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner # 1. 指定方法上添加裝飾器 # class Foo(View): # # @method_decorator(wrapper) # def get(self,request): # pass # # def post(self,request): # pass # 2. 在類上添加 # @method_decorator(wrapper,name='dispatch') # class Foo(View): # # def get(self,request): # pass # # def post(self,request): # pass
a. 放置在data中攜帶 <form method="POST" action="/csrf1.html"> {% csrf_token %} <input id="user" type="text" name="user" /> <input type="submit" value="提交"/> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm(){ var csrf = $('input[name="csrfmiddlewaretoken"]').val(); var user = $('#user').val(); $.ajax({ url: '/csrf1.html', type: 'POST', data: { "user":user,'csrfmiddlewaretoken': csrf}, success:function(arg){ console.log(arg); } }) } </script> b. 放在請求頭中 <form method="POST" action="/csrf1.html"> {% csrf_token %} <input id="user" type="text" name="user" /> <input type="submit" value="提交"/> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"></script> <script> function submitForm(){ var token = $.cookie('csrftoken'); var user = $('#user').val(); $.ajax({ url: '/csrf1.html', type: 'POST', headers:{'X-CSRFToken': token}, data: { "user":user}, success:function(arg){ console.log(arg); } }) } </script>
# 若是傳入函數名,將會自動執行函數並取到值。 {% for a in page_info.pager %} {{ a|safe }} #xss攻擊 {% endfor %} index.html <select name="class_id"> <!-- 循環全部的班級 --> {% for row in class_list %} <!-- 若是是當前學生所在班級,則默認選中 --> {% if row.id == current_student_info.class_id %} <option selected value="{{ row.id }}">{{ row.title }}</option> {% else %} <option value="{{ row.id }}">{{ row.title }}</option> {% endif %} {% endfor %} </select> {% for item in item_list %} <a>{{ item }}</a> {% endfor %} {{forloop.counter}} {{forloop.first}} {{forloop.last}} {% if ordered_warranty %} {% else %} {% endif %} result = {} for row in teacher_list: tid =row['tid'] if tid in result: result[tid]['titles'].append(row['title']) else: result[tid] = {'tid': row['tid'],'name':row['name'],'titles': [row['title'],]} return render(request,'teacher.html',{'teacher_list':result.values()}) 母版: <html> ... {% block s1 %} {%endblock%} ... {% block s2 %} {%endblock%} </html> 子板: {% extends "layout.html "%} {% block s1 %} <h1>fff</h1> {%endblock%} {% block s2 %} <h1>ffffff</h1> {%endblock%} layout.html {% block x1 %}{%endblock%} <h1>ff</h1> {% block x2 %}{%endblock%} <h1>2</h1>... {% block x3 %}{%endblock%} index.html {%extends 'layout'%} {% block x1 %}dfssssssdfsd{%endblock%} {% block x2 %}dfsdfsd{%endblock%} {% block x3 %}fff{%endblock%} 自定義模板語言函數 建立templatetags目錄,在其下建立xxx.py文件 使用特殊方法要先導入:{% load xx %} xxx.py from django import template register = template.Library() @register.filter # 只能有2個參數 def my_func(value,arg): return value+arg {{ name|my_func:"666"}} # 冒號後不能有空格 {%if name |my_func%} 〈h3〉真〈/h3〉 {%else%} 〈h3〉假</h3〉 {%endif%} #register.simple_tag # 可傳多個參數 def my_func(value,a1,a2,a3): return value+a1+a2+a3 {% my_func "a11" "a222" "a333" %} 小組件,可在頁面屢次加載,可不用{% load xx %}導入 {% include 'pub.html' %} pub.html <div> <h3>特別漂亮的組件</h3> <div class="title">標題:{{ name}}</div> <div class="content">內容:{{ name}}</div> </div> index.html <body>{% include 'pub.html' %}
Cookie a. 保存在客戶端瀏覽器上的「鍵值對」 b. 服務端能夠向用戶瀏覽器端寫cookie c. 客戶端每次方請求時,會攜帶cookie去 set_cookie key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, Https httponly=False 只能自Http請求中傳入,js代碼沒法獲取到 cookie簽名: obj = HttpResponse('...') obj.set_cookie('k1','v1') request.COOKIES.get('k1') obj.set_signed_cookie(k1,v1,max_age,salt='ff') request.get_signed_cookie('k1',salt='ff') session保持會話 Cookie是什麼? 保存在客戶端瀏覽器上的鍵值對 Session是什麼? 保存在服務端的數據(本質是鍵值對) 應用:依賴cookie 做用:保持會話(Web網站) # 登錄成功返回時,在request中設置session鍵值對後,將經過cookie發送隨機字符串 # session值保存在數據庫表中的 # 在瀏覽器請求時,獲取瀏覽器帶來的session隨機字符串,隨後檢測是否有這個用戶登陸 if 登錄成功: request.session['username']='name1' request.session['password']='pwd1' return render() 判斷是否登錄 v = request.session.get('username') if v:return HttpResponse('%s,登錄成功'%v)