您好,登錄后才能下訂單哦!
1、安裝Django
$ 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
2、安裝 mysqlclient$ pip3 install mysqlclient
如果報(bào)錯(cuò),請(qǐng)參考:https://blog.51cto.com/qiangsh/2422115
1:用戶(hù)打開(kāi)一個(gè)網(wǎng)址的步驟
從用戶(hù)角度分析一個(gè)框架(網(wǎng)站)都需要那些零件
經(jīng)典的MVC(MTV)框架是怎么來(lái)的呢?
2:以此設(shè)計(jì)邏輯分析django框架
首先創(chuàng)建django項(xiàng)目,查看下項(xiàng)目的目錄結(jié)構(gòu)
使用 django-admin 來(lái)創(chuàng)建 devops 項(xiàng)目:
django-admin.py startproject devops
查看項(xiàng)目的目錄結(jié)構(gòu):
$ tree devops/
├── devops
│?? ├── __init__.py
│?? ├── settings.py
│?? ├── urls.py
│?? └── wsgi.py
├── manage.py
目錄說(shuō)明:
2.1:訪(fǎng)問(wèn)URL——為啥訪(fǎng)問(wèn) http://ip/admin就訪(fǎng)問(wèn)到了管理后臺(tái)
# URL總?cè)肟?$ cat devops/urls.py
from django.contrib import admin
from django.urls import path
urlpatterns = [
# 訪(fǎng)問(wèn)admin的請(qǐng)求交給了admin.site.urls處理,而admin是django自帶的APP
path('admin/', admin.site.urls),
]
# devops項(xiàng)目總配置文件
$ cat devops/settings.py
……
# Django自帶的APP都已經(jīng)在這里注冊(cè)好了,我們自己定義的app也得在這里注冊(cè)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'hello.apps.HelloConfig', # 添加此行
]
……
# 這些django自動(dòng)的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這個(gè)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:用戶(hù)發(fā)出的請(qǐng)求是數(shù)來(lái)處理的呢
URL已經(jīng)將用戶(hù)請(qǐng)求帶到了admin的內(nèi)部。用戶(hù)訪(fǎng)問(wèn)admin后臺(tái)其實(shí)提交了兩個(gè)操作,第一是get請(qǐng)求admin頁(yè)面,admin給了一個(gè)列表框,要求填寫(xiě)用戶(hù)名密碼;第二個(gè)是post請(qǐng)求是把用戶(hù)密碼提交給admin,那么這兩個(gè)請(qǐng)求是誰(shuí)來(lái)處理的呢——view
# admin app的view目錄下編寫(xiě)應(yīng)對(duì)用戶(hù)請(qǐng)求的各種邏輯,源碼可自行查看
$ ls ~/env3/lib/python3.6/site-packages/django/contrib/admin/views/
autocomplete.py decorators.py __init__.py main.py
2.3:數(shù)據(jù)存在哪里?數(shù)據(jù)表結(jié)構(gòu)哪里定義的呢?vim ~/env3/lib/python3.6/site-packages/django/contrib/admin/models.py
2.4:用戶(hù)看的頁(yè)面各種樣式在哪里定義的呢?
$ 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
1、創(chuàng)建工程django-admin.py startproject devops
2、創(chuàng)建一個(gè)APP(應(yīng)用)
Django框架的組織架構(gòu):一個(gè)項(xiàng)目(Project)下可以有多個(gè)應(yīng)用(APP),每個(gè)應(yīng)用下面都五臟俱全的MTV模塊(就是以py結(jié)尾的文件),每個(gè)模塊各司其職。
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 # 后臺(tái)管理文件
├── apps.py # app命名文件
├── __init__.py # 初始化文件,有他表示這是一個(gè)包
├── migrations # 數(shù)據(jù)遷移文件
│ └── __init__.py
├── models.py # 模型文件
├── tests.py
├── urls.py # 定義路由,默認(rèn)沒(méi)有,自己加的
└── views.py # 邏輯處理,即控制器
2.1:全局配置文件中注冊(cè)新創(chuàng)建的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', # 添加此行
]
注釋下面一行,解決權(quán)限問(wèn)題
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:編寫(xiě)處理邏輯代碼(控制器)
$ cat hello/views.py
# Create your views here.
from django.shortcuts import render
from django.http import HttpResponse,QueryDict
# 練習(xí)一
# def index(request):
# return HttpResponse("<p>Hello World,Hello, Django</p>")
# 練習(xí)二
# 位置參數(shù)的接收方法---函數(shù)中的參數(shù)和URL中的位置一一對(duì)應(yīng)(嚴(yán)重依賴(lài)參數(shù)順序且代碼可讀性不好,不推薦)
def index(request,year=2018,month=8):
# 普通參數(shù)的接受方法
# 方法一、設(shè)置默認(rèn)值的方式獲取數(shù)據(jù)更優(yōu)雅
year = request.GET.get("year","2019")
# 方法二、直接獲取數(shù)據(jù),沒(méi)有傳值會(huì)報(bào)錯(cuò),不建議使用
month = request.GET["month"]
return HttpResponse("year is %s,month is %s" %(year,month))
# 關(guān)鍵字傳參數(shù)(?<參數(shù)名>參數(shù)類(lèi)型)——視圖中直接通過(guò)參數(shù)名獲取值(最常用)
def index2(request,**kwargs):
# 請(qǐng)求參數(shù)接收,默認(rèn)為GET請(qǐng)求,通過(guò)method判斷POST請(qǐng)求
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:編寫(xiě)提供給用戶(hù)訪(fǎng)問(wèn)的路由URL
URL的設(shè)計(jì)比較優(yōu)雅的方式:APP自己定義自己的url,然后在全局統(tǒng)一入口的url文件中引入即可
#設(shè)計(jì)自己的url, 用戶(hù)訪(fǎng)問(wèn)/hello就會(huì)把請(qǐng)求發(fā)給views模塊中的index方法
$ cat hello/urls.py # 系統(tǒng)沒(méi)有,需要自己建立
from django.urls import path,re_path
from . import views
urlpatterns = [
# 2.3.1:普通傳參url基本和無(wú)參數(shù)一樣
# 請(qǐng)求方式 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中每個(gè)位置數(shù)值和view中定義的參數(shù)順序一一對(duì)應(yīng)(代碼可讀性不好,不推薦)
# 2.3.2:位置匹配
# 請(qǐng)求方式 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:關(guān)鍵字匹配(最優(yōu)雅) (?<參數(shù)名>參數(shù)類(lèi)型)??視圖中直接通過(guò)參數(shù)名獲取值(最常用)
re_path('user/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.user, name='user'),
]
#在統(tǒng)一訪(fǎng)問(wèn)url入口將hello的url引入進(jìn)來(lái)(注冊(cè)子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"),
]
# 總?cè)肟谖募侄嗔艘粚勇窂剑宰罱K的訪(fǎng)問(wèn)路徑為 http://ip:8000/hello/<app_url>/
#最終路徑如下
$ tree
.
├── devops # devops工程自動(dòng)的全局app
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py # 全局路由入口
│ └── wsgi.py
├── hello # 自己創(chuàng)建的app
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py # 每個(gè)app自定義的路由入口,需要注冊(cè)
│ └── views.py
└── manage.py
3 directories, 13 files
3、啟動(dòng)工程
python manage.py runserver 0.0.0.0:8000
小結(jié)
以上這個(gè)小栗子其實(shí)只用到了MTV中的View以及URL(url是view的指引,這兩個(gè)會(huì)一起出現(xiàn),統(tǒng)稱(chēng)為V),數(shù)據(jù)庫(kù)和模板都沒(méi)用上,故而體驗(yàn)不好,功能也簡(jiǎn)單,好歹是跑通了。接下來(lái)一個(gè)完整的項(xiàng)目。在此之前把V和URL的最佳實(shí)戰(zhàn)知識(shí)學(xué)習(xí)下
hello的小栗子主要實(shí)現(xiàn)了用戶(hù)發(fā)起請(qǐng)求,然后Django根據(jù)用戶(hù)發(fā)起的url路徑找到對(duì)應(yīng)的處理函數(shù),然后將內(nèi)容簡(jiǎn)單返回而已。但現(xiàn)實(shí)中用戶(hù)的請(qǐng)求可不是這么簡(jiǎn)單。用戶(hù)都會(huì)有那些請(qǐng)求呢,大致可以分為兩類(lèi)讀和寫(xiě),讀有帶參數(shù)和不帶參數(shù)兩種場(chǎng)景,寫(xiě)肯定是帶參數(shù)了
Django的MTV模式本質(zhì)上和MVC是一樣的,也是為了各組件間保持松耦合關(guān)系,只是定義上有些許不同
Django的MTV分別是值:
4、添加html文件
#添加模板目錄 'DIRS': []
$ cat devops/settings.py
TEMPLATES = [
{
# 模板引擎,翻譯給前端展示
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# 模板目錄,當(dāng)前目錄下創(chuàng)建templates
'DIRS': [BASE_DIR+"/templates"],
# 如果統(tǒng)一目錄沒(méi)有,就在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 是一個(gè)指向?qū)崿F(xiàn)了Django模板后端API的模板引擎類(lèi)的帶點(diǎn)的Python路徑。內(nèi)置的后有django.template.backends.django.DjangoTemplates 和 django.template.backends.jinja2.Jinja2.兩個(gè)模板差不多
* DIRS 定義了一個(gè)目錄列表,模板引擎按列表順序搜索這些目錄以查找模板源文件。默認(rèn)會(huì)先找templates目錄
* APP_DIRS 告訴模板引擎是否應(yīng)該進(jìn)入每個(gè)已安裝的應(yīng)用中查找模板。每種模板引擎后端都定義了一個(gè)慣用的名稱(chēng)作為應(yīng)用內(nèi)部存放模板的子目錄名
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訓(xùn)練營(yíng)</title>
<head>
<body >
myname is {{ user.name }}, age is {{ user.age }}
</body>
</html>
5、瀏覽器訪(fǎng)問(wèn)
5.1:帶參數(shù)的讀——get
# 普通參數(shù)
http://127.0.0.1:8000/hello/index/?year=2019&month=10
# 位置參數(shù)
http://127.0.0.1:8000/hello/hello/2018/01/
5.2:帶參數(shù)的寫(xiě)——post
#shell終端,模擬django表單POST提交數(shù)據(jù)
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/
6、QueryDict
通過(guò)上面演示我們知道無(wú)論GET/POST請(qǐng)求,接受參數(shù)的數(shù)據(jù)類(lèi)型都是QueryDict。QueryDict到底做了什么事情呢
在HttpRequest 對(duì)象中,GET 和POST 屬性是django.http.QueryDict 的實(shí)例,它是一個(gè)自定義的類(lèi)似字典的類(lèi),用來(lái)處理同一個(gè)鍵帶有多個(gè)值。無(wú)論使用GET,POST方式,他們最終都是通過(guò)QueryDict方法對(duì)傳入的參數(shù)進(jìn)行處理
# QueryDict常用方法
>>> QueryDict('a=1&a=2&c=3') # 對(duì)用戶(hù)請(qǐng)求的數(shù)據(jù)處理
<QueryDict: {'a': ['1', '2'], 'c': ['3']}>
>>> QueryDict.get(key, default=None) # 獲取數(shù)據(jù)
>>> 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'}
1、修改邏輯代碼
$ 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})
2、修改html頁(yè)面
$ 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 >
{# 接受列表的第N個(gè)值,很low不推薦 #}
<li>{{books.0}}</li>
<li>{{books.1}}</li>
<li>{{books.2}}</li>
<li>{{books.3}}</li>
{# for循環(huán)標(biāo)簽 ,渲染books列表 #}
{% for book in books %}
<li>{{book}}</li>
{% endfor %}
{# 接受字典中的定義的值 #}
<div >hello my name is {{people.name}} </br>
my age is {{ people.age }} and I am {{ people.sex }}
</div>
{# if標(biāo)簽使用,判斷user是否存在 #}
{% if people %}
<li>name:{{people.name}}</li>
{% else %}
用戶(hù)不存在
{% endif %}
{# for循環(huán)輸出字典里所有的key,value #}
{% for k,v in people.items %}
<li>{{k}}-->{{v}}</li>
{% endfor %}
{# 列表頁(yè)展示 #}
{% for product in products %}
<li>ID:{{product.pid}},Name:{{product.name}}</li>
{% endfor %}
{# 列表頁(yè)展示,表格輸出 #}
<table border="1">
<thead> {# 定義表格的表頭 #}
<tr> {# 行 #}
<th>ID</th> {# 表頭單元格 - 包含表頭信息 #}
<th>商品名</th>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td> {{product.pid}} </td> {# 標(biāo)準(zhǔn)單元 - 包含數(shù)據(jù) #}
<td> {{product.name}} </td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
3、瀏覽器訪(fǎng)問(wèn)
http://127.0.0.1:8000/hello/user/2019/08/
1、修改邏輯代碼
$ cat hello/views.py
#添加模塊
from django.http import HttpResponse, QueryDict, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
#新建登錄函數(shù)
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})
2、創(chuàng)建登錄html
$ cat templates/login.html
<html>
<body>
<!--登陸表單-->
<form action="{% url 'hello:login' %}" method="post">
<!--用戶(hù)名-->
<input name="username" type="text" placeholder="用戶(hù)名"> </br>
<!--密碼-->
<input name="password" type="password" placeholder="密碼"> </br>
<button type="submit">登錄</button>
</form>
{% if data %}
<h2>{{ data }}</h2>
{% endif %}
</body>
</html>
3、路由
$ 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'),
]
4、瀏覽器訪(fǎng)問(wèn)
http://127.0.0.1:8000/hello/login/
用戶(hù)名密碼錯(cuò)誤,效果如下。
輸入正確 跳轉(zhuǎn)http://127.0.0.1:8000/hello/index2/
模板template如何接收View的各種數(shù)據(jù)類(lèi)型并渲染已經(jīng)完成,但頁(yè)面還是不夠美麗,就得引出前端內(nèi)容了——Bootstrap(HTML/CSS/Jquery)
學(xué)習(xí)網(wǎng)站:
https://v3.bootcss.com/
https://v3.bootcss.com/css/
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。