問題1:HTTP請求過來會先到Django的那個地方?
先到urls.py ,裏面寫的是對應關係,1個URL對應1個函數名。
若是發URL請求過來,到達這裏,而後幫你去執行指定的函數,函數要作哪些事?
給客戶端瀏覽器返回字符串,只不過返回形式不同。
路由系統: url.py
視圖函數 : views.py
-數據庫操做 models.py
-模板引擎渲染
- -render(request,'/path/a.html')
- 若是遇到特殊的標籤好比{{ name }} ,他就會把它替換掉,會把name對應的root替換掉
- -render(request,'/path/a.html',{‘name’: ‘root’})
流程以下:
請求到來以後到達視圖函數,視圖函數幫助處理返回內容,處理階段,會用到模板引擎渲染,完過後返回給用戶。
1、數據庫操做的增刪改查
實例: 基本curd
一、數據庫設計
id hostname ip port status
二、在數據庫生成表
三、請求過來,先去處理請求,寫上url ,
去數據庫拿數據返回給用戶。
功能實現:
預備階段:
建立project
- django-admin startproject mysite ,
建立app
- cd mysite python manage.py startapp app01,
配置模板路徑
- settings.py裏面找TEMPLATE裏有個DIRS:【os.path.join(BASE_DIR,'templates'),】,
配置靜態文件
- os.path.join(BASE_DIR,'static'),
URL:
a. /servers ==>對應函數server處理
views:
a 數據庫獲取數據
寫一個:
servers.html
此時個人views.py寫法以下:
- # return HttpResponse('OK')
- # return render(request,'servers.html')
- # return render(request,'server.tpl',{})
- # return render(request,'server.txt')
- 'k4':{'name':'alex','age':15},
用戶發來請求,要把全部的數據列出來。
跟數據庫相關:
讓Django控制那些APP可以生產庫和表,這裏要在settings.py 把APP註冊進入,寫哪一個就建立哪一個的表,不寫數據庫的表生成不了。
進入app01修改models.py
先建立類:
- class UserInfo(models.Model):
- nid = models.AutoField(primary_key=True)
- username = models.CharField(max_length=32)
- pwd = models.CharField(max_length=64)
- age = models.IntegerField()
第2個是自增,3是字符串,4也是字符串,5是數字
而後執行:
- python manage.py makemigrations
執行完了之後呢,就會生成這麼額一個數據,在db.sqlite3裏面生成表
這裏須要注意事項:
一、settings.py要註冊app名字
二、若是是連接mysql,須要手動建立庫名,而後在settings.py中配置。
- django默認連接mysql用的是mysqlDb,這個模塊只在Python2有,在Python3沒有
- 放在django目錄下面有一個__init__.py,以下圖所示:
- 那麼他就會自動修改默認爲pymysql來連接數據庫。
類===表
字段==列
對象==一行數據
下面手動數據一些數據,來作一個數據庫獲取全部並展現的例子:
步驟1:
手動插入數據以下:
步驟2:
修改view函數
- server_list = models.UserInfo.objects.all()
- #獲得的是一個對象列表[userinfo(id=1,username=root,age=18),..]
- # for row in server_list:
- # print(row.nid,row.username,row.pwd,row.age)
- return render(request,'servers.html',{'server_list':server_list})
步驟3:
修改HTML
- {% for row in server_list %}
- <li>{{ row.nid }}-{{ row.username }}-{{ row.pwd }}-{{ row.age }}</li>
最後效果以下:
流程以下:
請求到來URL,對應關係,URL對應函數,函數執行數據庫操做,用戶返回內容,有返回字符串和返回並渲染。
擴展:
頁面點擊添加按鈕跳轉,加入a標籤
通常狀況下,GET請求通常來講就是獲取看到這個頁面,點擊也能夠往URL提交,只不過method換成post了。
只有post的時候才能獲取數據,因此要作一個判斷。
用戶發過來的數據都在request.POST裏面
實現功能:跳轉到新的頁面,增長一條數據後,在跳轉到原頁面
修改views.py
- if request.method == 'GET':
- return render(request,'add_user.html')
- elif request.method == 'POST':
- u = request.POST.get('user')
- p = request.POST.get('pwd')
- a = request.POST.get('age')
- # obj = models.UserInfo(username=u,pwd=p,age=a)
- models.UserInfo.objects.create(username=u,pwd=p,age=a)
- return redirect('/users')
新增add_user.html
- <form action="/add_user" method="POST">
- <p><input type="text" name="user" placeholder="用戶名"></p>
- <p><input type="password" name="pwd" placeholder="密碼"></p>
- <p><input type="text" name="age" placeholder="年齡"></p>
- <input type="submit" value="提交">
在servers.html裏面添加一個跳轉a 標籤
- <a href="/add_user">添加</a>
擴展:
新增刪除
步驟1:
URL
- url(r'^del_user$', views.del_user),
步驟2:
新增views.py文件
- nnid = request.GET.get('nid')
- # models.UserInfo.objects.all().delete()#刪除整個表數據
- models.UserInfo.objects.filter(nid=nnid).delete()
- return redirect('/users')
步驟3,修改HTML文件
- {% for row in server_list %}
- <li>{{ row.nid }}-{{ row.username }}-{{ row.pwd }}-{{ row.age }}-<a href="/del_user?nid={{ row.nid }}">刪除</a></li>
實現效果:
能夠再頁面上刪除
===========分割線===========
請求來了,先到URL,而後對應函數,去數據庫拿數據,而後渲染,返回
擴展,新增編輯
步驟1:
URL
- url(r'^edit_user$', views.edit_user),
步驟2:
新增views.py文件
- if request.method == 'GET':
- nnid = request.GET.get('nid')
- # v = models.UserInfo.objects.filter(nid=nnid)
- v = models.UserInfo.objects.filter(nid=nnid).first()
- #獲取的是對象列表 [UserInfo(),],永遠獲取的是一個列表,不是對象,以下
- #<QuerySet [<UserInfo: UserInfo object>]>
- print(v.nid,v.username,v.pwd,v.age)
- return render(request,'edit_user.html',{'obj':v})
- elif request.method == 'POST':
- nnid = request.POST.get('nid')
- u = request.POST.get('user')
- p = request.POST.get('pwd')
- a = request.POST.get('age')
- # obj = models.UserInfo.objects.filter(nid=nnid).first()
- models.UserInfo.objects.filter(nid=nnid).update(username=u,pwd=p,age=a)
- return redirect('/users')
步驟3:
新增HTML
- <form action="/edit_user" method="POST">
- <p style="display: none;"><input type="text" name="nid" placeholder="ID" value="{{ obj.nid }}"></p>
- <p><input type="text" name="user" placeholder="用戶名" value="{{ obj.username }}"></p>
- <p><input type="password" name="pwd" placeholder="密碼" value="{{ obj.pwd }}"></p>
- <p><input type="text" name="age" placeholder="年齡" value="{{ obj.age }}"></p>
- <input type="submit" value="提交">
有點須要提到就是:
在寫urls.py裏面,正確的URL寫法以下:
- url(r'^edit_user$', views.edit_user),
SEO看到這個
會認爲是個動態頁面,權重會低一些,若是改爲
會認爲是一個靜態,權重會高點,便於搜索引擎優化。
怎麼讓我寫一個URL來匹配全部的呢?正則匹配有-d
動態路由:
接下來就寫一個-的形式。爲了利於SEO搜索引擎優化。
我想寫到一個只寫1個URL匹配多個,正則表達式裏面有一個-d,匹配數字
- url(r'^edit_user-(\d+).html$', views.edit_user),
那麼傳遞的時候也應該把這個數字獲取到,不能以GET形式傳,若是是?形式能夠用GET
可是,函數必需要拿到這個ID,如何傳遞呢?
那就在函數裏面在加一個參數
- def edit_user(request,a1):
這個就是以URL的方式傳了,而不是GET形式。注意上面的a1能夠是任何
若是有2個佔位符,那麼後面傳參害的加個數字。
- def edit_user(request,a1,a2):
- return HttpResponse(a1+'--'+a2)
- url(r'^edit_user-(\d+)-(\d+).html$', views.edit_user),
- 可是它這個是按照順序傳送的,經過這種方式也能夠傳值,可是呢,他是依賴順序的。
接下來我給正則表達式寫個名字。
?P<n1>
寫法以下:
正則表達式仍是\d+,我加上N1和N2說明函數裏面必須有N1和N2,其餘不行
- url(r'^edit_user-(?P<n1>\d+)-(?P<n2>\d+).html$', views.edit_user),
函數變爲
- def edit_user(request,n1,n2):
- return HttpResponse(n1+'--'+n2)
這樣傳值跟位置沒有關係了,叫作動態路由方式
下面就是基於這個來進行修改成動態路由
函數修改:
- def edit_user_new(request,nnid):
- if request.method == 'GET':
- obj = models.UserInfo.objects.filter(nid=nnid).first()
- return render(request,'edit_user_new.html',{'obj':obj})
- elif request.method == 'POST':
- u = request.POST.get('user')
- p = request.POST.get('pwd')
- a = request.POST.get('age')
- models.UserInfo.objects.filter(nid=nnid).update(username=u,pwd=p,age=a)
- return redirect('/users')
URL修改
- url(r'^edit_user_new-(?P<nnid>\d+).html$', views.edit_user_new),
HTML修改
- <form method="POST" action="edit_user_new-{{ obj.nid }}.html">
- {# <p style="display: none;"><input type="text" name="nid" placeholder="ID" value="{{ obj.nid }}"></p>#}==>這個就不須要了
- <p><input type="text" name="user" placeholder="用戶名" value="{{ obj.username }}"></p>
- <p><input type="password" name="pwd" placeholder="密碼" value="{{ obj.pwd }}"></p>
- <p><input type="text" name="age" placeholder="年齡" value="{{ obj.age }}"></p>
- <input type="submit" value="提交">
關鍵在第一行
接着擴展,在URL裏面加個name='nnn' ,給URL 起一個別名,這樣他就能反生一個URL
代指的就是URL,這樣就能夠直接修改HTML,以下所示:
我修改URL,讓mmm對應的URL爲add_user
我在修改edit_user_new表單
在瀏覽器訪問,查看錶單,發現,mmm已經映射爲了add_user
可是若是URL有個動態的值,就不能直接這麼寫了,要寫成這樣子
- <form method="POST" action="{% url "nnn" nnid=obj.nid %}">
URL寫成
- url(r'^edit_user_new-(?P<nnid>\d+).html$', views.edit_user_new,name='nnn'),
這樣就經過別名直接反生URL了
對於沒有名字呢?直接加空格便可,最後總結爲幾個
之後會經過這種反生出來‘
別名理解就是,給一個URL 一個簡稱,這麼長的東西由這個來代替。
若是如今要寫個平臺,會有不少塊,若是都放在1個project下面,要建立多個APP
維護每個,就至關於1個業務,若是有人想修改URL,第一個部門要配置,第二個也要在settings.py配置,但會存在出錯。對於寫程序,不該該這樣弄,能夠這麼弄。在URL裏面修改成
- url(r'^app01/',include('app01.urls')),
- url(r'^app02/',include('app02.urls')),
- url(r'^app03/',include('app03.urls')),
這麼作的意思就是,至關於,我在設置裏規定,訪問帶了app01,那麼
把路由全部的關係放在app01裏面,而後我在app01裏面建立一個urls.py文件
修改地方以下:
一、修改全局的URL,如上
- url(r'^app01/',include('app01.urls')),
- url(r'^app02/',include('app02.urls')),
二、每一個APP裏面新增urls
三、修改函數
四、頁面測試訪問
小結:
之後就把URL作了一個分發
So
URL這須要記住4點:
一、一個URL對應1個函數,定死的
二、URL存在正則表達式,對應函數,相似1批URL對應函數處理
三、URL後面能夠加別名,經過別名反生出URL
四、對於URL說能夠進行分發。(重點)
視圖函數
return值
獲取請求信息:
request.POST
request.GET
request.method
request.FILES 經過它能夠上傳文件。
具體作法,我在app01裏面定義url和views函數
- url(r'^test$', views.test),
定義函數
- if request.method == 'GET':
- return render(request,'upload.html')
- elif request.method == 'POST':
- obj = request.FILES.get('fafafa')
- f = open(os.path.join('upload',obj.name),'wb')
- for line in obj.chunks():
- return HttpResponse('test')
還須要在project目錄下建一個upload目錄
最後顯示以下:
還有一個request.body,它是幹嗎的額呢?request.POST數據就是從它這裏取出來的。
若是有form表單像後臺提交數據,有請求頭和請求的內容
以下:
請求頭跟請求體分割是以2個\r\n來實現。
寫了一大堆規則,請求頭直接用1個\r\n分割,請求頭和請求體2個\r\n分割。
POST是對body 的一個處理。
1個返回字符串,1種返回頁面,1種返回跳轉
5、模板引擎
本質上就是幫助咋們作替換,有特殊規則:
特殊規則:
{ { k1 }} 獲取單值
二、
{% if a == 123 %}
{% endif %}
三、
{% for item in LIST % }
四、
#索引 : 字典的話就是 字典.k1 列表的話就是 列表.1
五、字符串所有變成大寫
模板語言也有不少方法
- url(r'^tpl.htm$', views.tpl),
- return render(request,'tpl.html',{'summary':'dfdsfdsffffffffffdddddddddddfdfd'})
- {{ summary|truncatechars:8 }}
內部提供的功能不夠咱們使用,咱們能夠自定義
須要自定義一些東西,以下:
步驟以下:
一、建立
二、建立 文件
寫函數,若是普通函數Django不認識,就要裝一個裝飾器
名字register不能修改,寫成其餘的不會認,這樣函數就已經生效了。
- from django import template
- register = template.Library()
三、HTML要導入一下
四、settings.py裏面要註冊這個app01,裏面的東西才能生效
最終效果
函數裏的value是什麼呢?就是前面的summary
效果以下:
那麼:
冒號後面的值是第2個參數,以下
函數
結果以下:
這個就是自定製函數樂,那麼有何做用呢?
讓他幫忙生成一個input框,或者1個a標籤
以HTML形式顯示,就須要作一個處理
- from django.utils.safestring import mark_safe
就會以原生的HTML顯示了,不軟傳的就是一個字符串
函數形式爲
HTML
最後形式以下:
上面叫作頁面自定義filter,那有限制嗎?
對於filter,最多隻有2個參數,下面要說的就是@register.simple_tag 參數沒有限制了
修改函數
修改HTML
顯示:
simple_tag優點就是參數沒限制。
可是呢。filter有一個優點
就是在模板語言中支持if條件
若是作條件用filter,若是僅僅只是返回內容就用simple_tag
總結:
接下來,寫一個例子:
後臺管理,模板有重合的地方,頁面作一個修改
這裏就涉及到了一個繼承的概念。
新創建一個layout.html文件,讓內容可以變更便可。其餘的繼承便可
- {% block css %}{% endblock %}
- <div class="pg-header"></div>
- <div class="menus"></div>
- {% block bd %}{% endblock %}
- {% block js %}{% endblock %}
groups.html修改以下。
第一行就是引入:要繼承 誰,而後下面是3個塊
- {% extends 'layout.html' %}
至關於搞了一個父頁面,全部子頁面繼承父頁面
最後頁面效果是同樣的,
因此
通常狀況下,預留位置仍是預留3塊,css 內容 以及js
下面作一個分頁頁碼,小組件用上面是不合適的,推薦使用include這個,導入一個小組件
好比我想導入一個分頁
相似下面,這個
放哪裏比較合適呢?
寫一個pager.html
而後在引用一下
效果同樣的
後臺管理,只有登陸成功以後才能看,如何實現呢?
http請求是短連接,斷開之後在過來,我就不認識了。這樣每次去都要登錄一次,這是咱們不想要的。
登陸的時候,口袋放一個東西,而後在user函數裏面判斷,這個東西就是cookie
6、cookie
每一次來訪問,先去瀏覽器拿東西,拿完東西之後來作檢測是否已經登陸成功,
這個cookie是什麼呢?
是用戶瀏覽器上的一個鍵值對、
這個東西怎麼看嗯?
除了作登陸,還能作不少事情,好比頁面上有個後臺管理,能夠任意調整。
還有一個就是頁面默認顯示10天,左下角有個默認調整100條,都是基於cookie來作的
而cookie就是默認保存在瀏覽器上的一個鍵值對。
若是提到cookie的時候,就告訴他。
它就是一個保存在瀏覽器的一個鍵值對,利用它能夠實現登陸驗證以及頁面顯示條數還有拖動位置等等。
把信息放到cookie保存了,那他多長時間消失呢?
就是鍵值對,過了時間消失了,就沒有了,因此須要你從新登陸。因此對於這個簡直對來講,有個特殊性,能夠設置超時時間。
如何設置呢?
下面就是10s失效
還有一個到哪一個時間點失效
這裏還有一個path,這個cookie不是瞎寫的。由於網站有多個URL,在設置cookie的時候能夠設置在哪一個URL下生效。好比:不寫,就是全局生效,任何頁面都能拿到
默認path就是path='/' ,訪問任何都能獲取到
若是我寫爲path='/index'只有在訪問index的時候會帶這個值過來,有了路徑,還有域名
domain=' ' 訪問域名生效。不能瞎寫
httponly=True 只是HTTP傳輸
secure=True 就是HTTPS發送
驗證以下:
寫views.py
登陸函數
- if request.method == 'GET':
- return render(request,'login.html')
- elif request.method == 'POST':
- u = request.POST.get('user')
- p = request.POST.get('pwd')
- obj = models.UserInfo.objects.filter(username=u,pwd=p).first()
- #models.UserInfo.objects.filter(username=u,pwd=p).count()
- d = datetime.datetime.utcnow()
- m = datetime.timedelta(seconds=10)
- obj.set_cookie(key='user_name',value=u,max_age=10,expires=end)
- return render(request,'login.html',{'msg':'用戶名或密碼錯誤'})
頁面函數
- #若是去摸口袋,有就登陸,沒有就重定向到login頁面
- v = request.COOKIES.get('user_name')
- return redirect('/login')
登陸的html
- <form action="/login" method="POST">
- <p><input type="text" name="user"></p>
- <p><input type="password" name="pwd"></p>
- <input type="submit" value="登陸"> {{ msg }}
如今有個問題,就是好多頁面都要登陸成功以後才能訪問,那這個users函數就要寫多個,怎麼辦?寫個裝飾器便可。
7、session
兩大忌諱:
敏感信息
簡單值
session是什麼東西呢?它也是一個鍵值對,放在服務器端
首先確保session是放在服務器端的一個鍵值對。
這樣就設置了session,
- request.session['username'] = u
上面驗證也是從session去拿
這個session瀏覽器有一份,默認Django數據庫也有一份
具體實現:
修改函數
- if request.method == 'GET':
- return render(request,'login.html')
- elif request.method == 'POST':
- u = request.POST.get('user')
- p = request.POST.get('pwd')
- obj = models.UserInfo.objects.filter(username=u,pwd=p).first()
- #models.UserInfo.objects.filter(username=u,pwd=p).count()
- request.session['username'] = u
- return render(request,'login.html',{'msg':'用戶名或密碼錯誤'})
- #若是去摸口袋,有就登陸,沒有就重定向到login頁面
- v = request.session.get('username')
- return redirect('/login')
區別就是,session保存在服務端,cookie保存在瀏覽器
推薦登陸使用session來作,不要用cookie,可是呢,session依賴於cookie而存在。
Django進階篇,對於session有個簡要說明。
默認狀況下session的時間爲二週。
客戶端登陸一次,二週內都不用登陸,這個能夠修改,在settings.py裏配置。
這個都是默認的配置,能夠本身修改來作到本身想要的效果
cookie保存在瀏覽器的鍵值對
session保存在服務器端的鍵值對,不過要基於cookie
把下面這個寫成裝飾器。
最後實現的效果是同樣的
over!!