一、安裝Djangophp
$ pip install django==2.2.0 $ pip list Package Version ---------------- ------- backcall 0.1.0 decorator 4.4.0 Django 2.2 $ python -m django --version 2.2
二、安裝 mysqlclient$ pip3 install mysqlclient
css
若是報錯,請參考:http://www.javashuo.com/article/p-nhvdbece-gv.htmlhtml
1:用戶打開一個網址的步驟前端
從用戶角度分析一個框架(網站)都須要那些零件java
經典的MVC(MTV)框架是怎麼來的呢?python
2:以此設計邏輯分析django框架mysql
首先建立django項目,查看下項目的目錄結構web
使用 django-admin 來建立 devops 項目:sql
django-admin.py startproject devops
查看項目的目錄結構:shell
$ tree devops/ ├── devops │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py
目錄說明:
2.1:訪問URL——爲啥訪問 http://ip/admin就訪問到了管理後臺
# URL總入口 $ cat devops/urls.py from django.contrib import admin from django.urls import path urlpatterns = [ # 訪問admin的請求交給了admin.site.urls處理,而admin是django自帶的APP path('admin/', admin.site.urls), ] # devops項目總配置文件 $ cat devops/settings.py …… # Django自帶的APP都已經在這裏註冊好了,咱們本身定義的app也得在這裏註冊 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hello.apps.HelloConfig', # 添加此行 ] …… # 這些django自動的APP在哪呢? $ ls ~/env3/lib/python3.6/site-packages/django/contrib/ admin admindocs auth contenttypes flatpages gis humanize __init__.py messages postgres __pycache__ redirects sessions sitemaps sites staticfiles syndication # 找到admin這個APP的url $ vim ~/env3/lib/python3.6/site-packages/django/contrib/admin/sites.py …… def urls(self): return self.get_urls(), 'admin', self.name ……
2.2:用戶發出的請求是數來處理的呢
URL已經將用戶請求帶到了admin的內部。用戶訪問admin後臺其實提交了兩個操做,第一是get請求admin頁面,admin給了一個列表框,要求填寫用戶名密碼;第二個是post請求是把用戶密碼提交給admin,那麼這兩個請求是誰來處理的呢——view
# admin app的view目錄下編寫應對用戶請求的各類邏輯,源碼可自行查看 $ ls ~/env3/lib/python3.6/site-packages/django/contrib/admin/views/ autocomplete.py decorators.py __init__.py main.py
2.3:數據存在哪裏?數據表結構哪裏定義的呢?vim ~/env3/lib/python3.6/site-packages/django/contrib/admin/models.py
2.4:用戶看的頁面各類樣式在哪裏定義的呢?
$ ls ~/env3/lib/python3.6/site-packages/django/contrib/admin/templates/admin/ 404.html auth change_form_object_tools.html date_hierarchy.html filter.html login.html prepopulated_fields_js.html 500.html base.html change_list.html delete_confirmation.html includes object_history.html search_form.html actions.html base_site.html change_list_object_tools.html delete_selected_confirmation.html index.html pagination.html submit_line.html app_index.html change_form.html change_list_results.html edit_inline invalid_setup.html popup_response.html widgets
一、建立工程django-admin.py startproject devops
二、建立一個APP(應用)
Django框架的組織架構:一個項目(Project)下能夠有多個應用(APP),每一個應用下面都五臟俱全的MTV模塊(就是以py結尾的文件),每一個模塊各司其職。
qiangsh@Dream ~/D/P/5/Django_day1> cd devops/ qiangsh@Dream ~/D/P/5/D/devops> python manage.py startapp hello qiangsh@Dream ~/D/P/5/D/devops> tree hello hello ├── admin.py # 後臺管理文件 ├── apps.py # app命名文件 ├── __init__.py # 初始化文件,有他表示這是一個包 ├── migrations # 數據遷移文件 │ └── __init__.py ├── models.py # 模型文件 ├── tests.py ├── urls.py # 定義路由,默認沒有,本身加的 └── views.py # 邏輯處理,即控制器
2.1:全局配置文件中註冊新建立的APP
$ cat devops/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hello.apps.HelloConfig', # 添加此行 ]
註釋下面一行,解決權限問題
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', #註釋此行,解決跨域 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
2.2:編寫處理邏輯代碼(控制器)
$ cat hello/views.py # Create your views here. from django.shortcuts import render from django.http import HttpResponse,QueryDict # 練習一 # def index(request): # return HttpResponse("<p>Hello World,Hello, Django</p>") # 練習二 # 位置參數的接收方法---函數中的參數和URL中的位置一一對應(嚴重依賴參數順序且代碼可讀性很差,不推薦) def index(request,year=2018,month=8): # 普通參數的接受方法 # 方法1、設置默認值的方式獲取數據更優雅 year = request.GET.get("year","2019") # 方法2、直接獲取數據,沒有傳值會報錯,不建議使用 month = request.GET["month"] return HttpResponse("year is %s,month is %s" %(year,month)) # 關鍵字傳參數(?<參數名>參數類型)——視圖中直接經過參數名獲取值(最經常使用) def index2(request,**kwargs): # 請求參數接收,默認爲GET請求,經過method判斷POST請求 if request.method == "POST": print(request.scheme) # http #print(request.method) #POST print(request.body) #b'year=2019&month=11' #print(type(request.body)) print(QueryDict(request.body).dict()) #{'year': '2018', 'month': '08'} #print(type(QueryDict(request.body).dict())) print(request.POST) #<QueryDict: {'year': ['2018'], 'month': ['08']}> print(type(request.POST)) #<class 'django.http.request.QueryDict'> data = request.POST year = data.get('year',2018) month = data.get('month',8) else: print(request) print(request.method) print(request.META) print(request.body) print(kwargs) year = kwargs.get('year',2018) month = kwargs.get('month',8) return HttpResponse("year is %s,month is %s" %(year,month)) def user(request,**kwargs): if request.method == "POST": pass else: user = {'name':'qsh','age':'18'} return render(request,'index.html',{'user':user})
2.3:編寫提供給用戶訪問的路由URL
URL的設計比較優雅的方式:APP本身定義本身的url,而後在全局統一入口的url文件中引入便可
#設計本身的url, 用戶訪問/hello就會把請求發給views模塊中的index方法
$ cat hello/urls.py # 系統沒有,須要本身創建 from django.urls import path,re_path from . import views urlpatterns = [ # 2.3.1:普通傳參url基本和無參數同樣 # 請求方式 http://127.0.0.1:8000/hello/hello/?year=2019&month=10 path('index/', views.index, name='index'), path('hello/',views.index2, name='index'), # URL中每一個位置數值和view中定義的參數順序一一對應(代碼可讀性很差,不推薦) # 2.3.2:位置匹配 # 請求方式 http://127.0.0.1:8000/hello/hello/2019/08/ re_path('hello/([0-9]{4})/([0-9]{2})/', views.index2, name='index2'), # 2.3.3:關鍵字匹配(最優雅) (?<參數名>參數類型)??視圖中直接經過參數名獲取值(最經常使用) re_path('user/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.user, name='user'), ]
#在統一訪問url入口將hello的url引入進來(註冊子app的url)
$ cat devops/urls.py from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('hello/',include('hello.urls'),name="hello"), ] # 總入口文件又多了一層路徑,因此最終的訪問路徑爲 http://ip:8000/hello/<app_url>/
#最終路徑以下
$ tree . ├── devops # devops工程自動的全局app │ ├── __init__.py │ ├── settings.py │ ├── urls.py # 全局路由入口 │ └── wsgi.py ├── hello # 本身建立的app │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── urls.py # 每一個app自定義的路由入口,須要註冊 │ └── views.py └── manage.py 3 directories, 13 files
三、啓動工程
python manage.py runserver 0.0.0.0:8000
小結
以上這個小栗子其實只用到了MTV中的View以及URL(url是view的指引,這兩個會一塊兒出現,統稱爲V),數據庫和模板都沒用上,故而體驗很差,功能也簡單,好歹是跑通了。接下來一個完整的項目。在此以前把V和URL的最佳實戰知識學習下
hello的小栗子主要實現了用戶發起請求,而後Django根據用戶發起的url路徑找到對應的處理函數,而後將內容簡單返回而已。但現實中用戶的請求可不是這麼簡單。用戶都會有那些請求呢,大體能夠分爲兩類讀和寫,讀有帶參數和不帶參數兩種場景,寫確定是帶參數了
Django的MTV模式本質上和MVC是同樣的,也是爲了各組件間保持鬆耦合關係,只是定義上有些許不一樣
Django的MTV分別是值:
四、添加html文件
#添加模板目錄 'DIRS': []
$ cat devops/settings.py TEMPLATES = [ { # 模板引擎,翻譯給前端展現 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 模板目錄,當前目錄下建立templates 'DIRS': [BASE_DIR+"/templates"], # 若是統一目錄沒有,就在app本身目錄查找 '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', ], }, }, ] #配置解釋 * BACKEND 是一個指向實現了Django模板後端API的模板引擎類的帶點的Python路徑。內置的後有django.template.backends.django.DjangoTemplates 和 django.template.backends.jinja2.Jinja2.兩個模板差很少 * DIRS 定義了一個目錄列表,模板引擎按列表順序搜索這些目錄以查找模板源文件。默認會先找templates目錄 * APP_DIRS 告訴模板引擎是否應該進入每一個已安裝的應用中查找模板。每種模板引擎後端都定義了一個慣用的名稱做爲應用內部存放模板的子目錄名
qiangsh@Dream ~> cd devops qiangsh@Dream ~/devops> mkdir templates/ qiangsh@Dream ~/devops> cat index.html <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <title>python訓練營</title> <head> <body style="background:blue"> myname is {{ user.name }}, age is {{ user.age }} </body> </html>
五、瀏覽器訪問
5.1:帶參數的讀——get
# 普通參數 http://127.0.0.1:8000/hello/index/?year=2019&month=10
# 位置參數 http://127.0.0.1:8000/hello/hello/2018/01/
5.2:帶參數的寫——post
#shell終端,模擬django表單POST提交數據 curl -X POST http://127.0.0.1:8000/hello/hello/ -d 'year=2019&month=11'
http://127.0.0.1:8000/hello/user/2019/08/
六、QueryDict
經過上面演示咱們知道不管GET/POST請求,接受參數的數據類型都是QueryDict。QueryDict到底作了什麼事情呢
在HttpRequest 對象中,GET 和POST 屬性是django.http.QueryDict 的實例,它是一個自定義的相似字典的類,用來處理同一個鍵帶有多個值。不管使用GET,POST方式,他們最終都是經過QueryDict方法對傳入的參數進行處理
# QueryDict經常使用方法 >>> QueryDict('a=1&a=2&c=3') # 對用戶請求的數據處理 <QueryDict: {'a': ['1', '2'], 'c': ['3']}> >>> QueryDict.get(key, default=None) # 獲取數據 >>> q = QueryDict('a=1&a=2&a=3') >>> q.lists() [('a', ['1', '2', '3'])] >>> q = QueryDict('a=1&b=3&c=5') >>> q.dict() {'a': '1','b':'3','c':'5'}
一、修改邏輯代碼
$ cat hello/views.py def user(request,**kwargs): if request.method == "POST": pass else: user = {'name':'qsh','age':'18'} title = "devops" books = ['python','java','php','web'] people = {'name':'qsh','age':18,'sex':'male'} products = [{'pid': 1, 'name': 'iphone'}, {'pid': 2, 'name': 'computer'}, {'pid': 3, 'name': 'TV'}] return render(request,'index.html',{'title':title,'books':books,'people':people,'user':user,'products':products})
二、修改html頁面
$ cat templates/index.html <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <title>{{title}}</title> <head> <body style="background:blue"> {# 接受列表的第N個值,很low不推薦 #} <li>{{books.0}}</li> <li>{{books.1}}</li> <li>{{books.2}}</li> <li>{{books.3}}</li> {# for循環標籤 ,渲染books列表 #} {% for book in books %} <li>{{book}}</li> {% endfor %} {# 接受字典中的定義的值 #} <div style="color:orangered">hello my name is {{people.name}} </br> my age is {{ people.age }} and I am {{ people.sex }} </div> {# if標籤使用,判斷user是否存在 #} {% if people %} <li>name:{{people.name}}</li> {% else %} 用戶不存在 {% endif %} {# for循環輸出字典裏全部的key,value #} {% for k,v in people.items %} <li>{{k}}-->{{v}}</li> {% endfor %} {# 列表頁展現 #} {% for product in products %} <li>ID:{{product.pid}},Name:{{product.name}}</li> {% endfor %} {# 列表頁展現,表格輸出 #} <table border="1"> <thead> {# 定義表格的表頭 #} <tr> {# 行 #} <th>ID</th> {# 表頭單元格 - 包含表頭信息 #} <th>商品名</th> </tr> </thead> <tbody> {% for product in products %} <tr> <td> {{product.pid}} </td> {# 標準單元 - 包含數據 #} <td> {{product.name}} </td> </tr> {% endfor %} </tbody> </table> </body> </html>
三、瀏覽器訪問
http://127.0.0.1:8000/hello/user/2019/08/
一、修改邏輯代碼
$ cat hello/views.py #添加模塊 from django.http import HttpResponse, QueryDict, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse #新建登陸函數 def login(request, **kwargs): data = "" if request.method == "POST": print(request.POST) print(QueryDict(request.body).dict()) username = request.POST.get('username','qsh') passwd = request.POST.get('password','123456') if username == "admin" and passwd == "123456": # data = "welcome you %s" % username return HttpResponseRedirect(reverse("hello:user")) # return HttpResponseRedirect("/hello/hello/") else: data = "your passwd or username is wrong,plaeace again" return render(request, 'login.html', {'data':data})
二、建立登陸html
$ cat templates/login.html <html> <body> <!--登錄表單--> <form action="{% url 'hello:login' %}" method="post"> <!--用戶名--> <input name="username" type="text" placeholder="用戶名"> </br> <!--密碼--> <input name="password" type="password" placeholder="密碼"> </br> <button type="submit">登陸</button> </form> {% if data %} <h1>{{ data }}</h1> {% endif %} </body> </html>
三、路由
$ cat hello/urls.py from django.urls import path,re_path from . import views app_name = 'hello' urlpatterns = [ path('index/', views.index, name='index'), path('hello/',views.index2, name='hello'), path('login/',views.login, name='login'), path('index2/',views.user, name='user'), re_path('hello/([0-9]{4})/([0-9]{2})/', views.index2, name='index2'), re_path('user/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.user, name='user'), ]
四、瀏覽器訪問
http://127.0.0.1:8000/hello/login/
用戶名密碼錯誤,效果以下。
輸入正確 跳轉http://127.0.0.1:8000/hello/index2/
模板template如何接收View的各類數據類型並渲染已經完成,但頁面仍是不夠美麗,就得引出前端內容了——Bootstrap(HTML/CSS/Jquery)