運行Django項目:
- 通過命令行的方式: python manage.py runserver 。在本地瀏覽器 http://127.0.0.1:8000/ 來訪問自己寫的網站啦。
- 如果想要修改端口號,在運行的時候可以指定端口號, python manage.py runserver 9000 這樣就可以通過 9000 端口來訪問啦。另外,這樣運行的項目只能在本機上能訪問。
- 如果想要在其他電腦上也能訪問本網站,那麼需要指定 ip 地址爲 0.0.0.0 。終端運行示例爲: python manage.py runserver 0.0.0.0:8000 。pycharm運行,右上角項目配置修改,如下:
4. 通過 pycharm 運行。直接點擊右上角的綠色箭頭按鈕即可運行。
注意:其他電腦必須和該電腦的iP在同一個局域網,也就是能ping通;且要關閉自己電腦的防火牆。除此之外,還要設置ALLOWED_HOSTS
:這裏設置爲本機的ip
ALLOWED_HOSTS
是爲了限定請求中的host
值,以防止黑客構造包來發送請求。只有在列表中的host
才能訪問。
如果設置爲*,則所有網址都可以訪問。
Django項目中project和app的關係:
app是django 項目的組成部分。一個app 代表項目中的一個模塊,所有 URL 請求的響應都是 由 app 來處理。比如豆瓣,裏面有圖書,電影,音樂,同城等許許多多的模塊,如果站 在 django 的角度來看,圖書,電影這些模塊就是 app ,圖書,電影這些app 共同組成豆瓣這個 項目。因此這裏要有一個概念,django 項目由許多app組成,一個app 可以被用到其他項目,django 也能擁有不同的 app 。
項目結構:
- manage.py :以後和項目交互基本上都是基於這個文件。一般都是在終端輸入 python manage.py [子命令] 。可以輸入 python manage.py help 看下能做什麼事情,一般情況下不要隨便編輯這個文件。
- settings.py :本項目的設置項,以後所有和項目相關的配置都是放在這個裏面。
- urls.py :這個文件是用來配置URL路由的。比如訪問 http://127.0.0.1/news/ 是訪問新聞 列表頁,這些東西就需要在這個文件中完成。
- wsgi.py :項目與 WSGI 協議兼容的 web 服務器入口,部署的時候需要用到的,一般情況下也是不需要修改的。
- APP下的index.thml:主要包含前端顯示和處理的代碼:h5(主要包含前端的顯示代碼,如:div塊、鏈接、table表格等)和js(用於處理前端後端交互時,前端的一下處理,如:查詢、填寫頁面數據、按鈕觸發、Ajax請求處理等)
- APP下的models.py:這個模塊就比較簡單、主要是用來定義項目所涉及的數據庫中表名和各字段類型,限制等。
- APP下視圖層view.py:這個模塊是用來定義後端處理的函數:如:後端查詢數據庫、詳情頁面請求數據、新增、刪除後端處理等等。
Django項目執行流程:
index.html爲前端顯示的頁面,裏面包含用戶處理的操作:如查詢、新增、刪除等等,當用戶觸發頁面的操作按鈕時,系統會去urls.py裏找路由(route),在urls.py匹配到對應的路徑後,就會去view.py執行後端代碼(後端的函數裏的參數時前端操作時帶過來的),執行完後端的操作,前端再接收,完成相應的前端處理。
詳解urls.py、index.thml、models.py及view.py
一. view.py
- 視圖一般都寫在 app 的 views.py 中。並且視圖裏所有函數的第一個參數永遠且必須是 request (一個 HttpRequest)對象。這個對象存儲了請求過來的所有信息,包括攜帶的參數以及一些頭部信息 等。
- 在視圖中,一般是完成邏輯相關的操作。比如這個請求是添加一篇博客,那麼可以通過 request來接收到這些數據,然後存儲到數據庫中,最後再把執行的結果返回給瀏覽器。視圖函數的返回結果必須是 HttpResponseBase 對象或者子類的對象。
- 我們常用的HttpResponseBase對象或者子類對象有:JsonResponse 和HttpResponse,其中HttpResponse是用的最多的子類;JsonResponse繼承了HttpResponse對象並進行二次封裝。
1、view.py裏的render方法、HttpResponse方法、JsonResponse方法
- render:可接收三個參數,一是request參數,二是待渲染的html模板文件,三是保存具體數據的字典參數。它的作用就是將數據填充進模板文件,最後把結果返回給瀏覽器。
- HttpResponse:它是作用是內部傳入一個字符串參數,然後發給瀏覽器,不能渲染html。 (如果是Ajax請求,建議永遠讓服務器返回一個字典(return HttpResponse(json.dumps(字典)),可以修改返回的數據類型(如前面那個json.dumps就是修改返回類型),比較適合返回圖片,視頻,音頻等二進制文件。
return HttpResponse(json.dumps(result), content_type="application/json")
#其中result是需要處理的字典鍵值對
return HttpResponse("請求路徑:{}".format(request.path))
#也可以設置固定返回數據
- JsonResponse:是HttpResponse的子類,內部強制做了json轉換,所以返回的一定是json,同時也支持了list的輸出
return JsonResponse(result, safe=False)
return JsonResponse('{"result": "刪除成功"}', safe=False)
三、視圖層request對象:
1. Request對象簡單實例
# views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello world")
# urls.py
from django.urls import re_path
from . import views
app_name = "Myapp"
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
]
因爲我們本例種不需要使用數據庫,所以不需要創建模型(models)。當你訪問http: // 127.0.0.1:8000 / index / 你就應該能看到hello world字樣。因爲這裏的index函數其實是沒有用到request的參數的,所以在編輯器裏面就是灰色的。
2. 現在我們將視圖函數稍微改下,使用request變量打印出請求路徑。
# views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("請求路徑:{}".format(request.path))
3. Request對象方法和屬性
(1)request.method:獲取請求方法(e.g.GET, POST).
(2)request.GET or request.POST:獲取GET or POST請求參數,字典形式。
(3)request.POST.get('name', default=None):獲取POST請求參數
(4)request.GET.getlist('name', default=None): 獲取GET參數列表
(5)request.META:包含當前HTTP請求的Headers頭部信息, 字典形式。鍵值KEY 都是大寫。如:request.META['REMOTE_ADDR']可獲取用戶遠程IP地址。
(6)request.user:獲取當前訪問用戶的所有信息。
(7)request.path:獲取當前訪問路徑。
4. 常用Request.META屬性
是一個Python字典,包含了所有本次HTTP請求的Header信息,常用屬性包括: REQUEST_METHOD: 當前請求方法, GET或POST
(1)request.META.get('HTTP_USER_AGENT', 'unknown'): 用戶瀏覽器的字符串, 比如Mozilla / 5.0(WindowsNT10.0;Win64;x64) AppleWebKit / 537.36。防止拋出錯誤異常。
(2)REMOTE_ADDR:客戶端IP地址,比如54.489.10201 。
(3)PATH_INFO: 當前路徑信息,如"/index", 等同於request.path
(4)如果想要知道META的所有屬性,可以在view.py裏寫一個函數:
def index(request):
values = request.META.items()
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return HttpResponse('<table>%s</table>' % '\n'.join(html))
5.完整的例子
# urls.py app級別的url
from django.urls import re_path
from . import views
app_name = "request_demo"
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
]
# views.py 這裏就是系統的後端的實現
from django.shortcuts import render
def index(request):
user = request.user
user_agent = request.META.get('HTTP_USER_AGENT', 'unknown')
ip = request.META['REMOTE_ADDR']
context = {'user': user, 'user_agent': user_agent, 'ip': ip, }
return render(request, "request_demo/index.html", context)
# MyApp/index.html
{% block content %}
<h3>MyApp</h3>
<ul>
<li>User: {{ user }}</li>
<li>User_Agent: {{ user_agent }}</li>
<li>IP Address: {{ ip }}</li>
</ul>
{% endblock %}
理解:view.py裏面的user,user_agent和ip都來自index.html;而index.html的這些數據是用戶一旦點擊該頁面,系統自動獲取到的。
二. index.html
- 前端界h5代碼和JS前端請求處理函數等,都存放在HTML裏
- 下面這段h5代碼,實現刪除界面
<!-- 刪除模態框-->
<div class="modal fade" id="delete-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">刪除</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>是否刪除?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" id="delete-btn" class="btn btn-danger">刪除</button>
</div>
</div>
</div>
</div>
- 下面這段JS代碼是實現:點擊刪除模態框,實現刪除功能
$("#delete-modal").on('show.bs.modal', function (event) {
var btnThis = $(event.relatedTarget); //觸發事件的按鈕
var currentDataId = btnThis.closest('tr').find('td').eq(0).text();//獲取某一列的內容eq後面表示列數\
$("#delete-btn").on('click',function() {
$.ajax({
url: "{% url 'mysite:delete' %}"+"?usrNm="+"{{usr_Nm}}"+"&usrId="+"{{usr_Id}}",
type: "POST",
data: {'IIID': currentDataId, csrfmiddlewaretoken: '{{ csrf_token }}'},
dataType: "JSON",
success:function (data) {
$('#delete-modal').modal('hide');
toastr.success(JSON.parse(data)['result']);
oTable.draw(false);
}
})
});
});
// 關閉刪除模態框時,解綁事件
$('#delete-modal').on('hide.bs.modal', function () {
$('#delete-btn').off('click');
});
三. models.py
models.py路徑在:APP下,主要用於存放數據庫信息,定義表名和字段名及類型,Meta是給這個類起的表名。
下面是其中一張表及字段名的定義
from django.db import models
class Bugs(models.Model):
filedagainst = models.CharField(db_column='filedAgainst', max_length=100, blank=True, null=True) # Field name made lowercase.
plannedfor = models.CharField(db_column='plannedFor', max_length=100, blank=True, null=True) # Field name made lowercase.
parentworkitemid = models.CharField(db_column='parentWorkitemId', max_length=100, blank=True, null=True) # Field name made lowercase.
workitemid = models.CharField(db_column='workItemId', primary_key=True, max_length=100) # Field name made lowercase.
summary = models.CharField(max_length=2000, blank=True, null=True)
description = models.CharField(max_length=2000, blank=True, null=True)
discover = models.CharField(max_length=100, blank=True, null=True)
resolvedby = models.CharField(db_column='resolvedBy', max_length=100, blank=True, null=True) # Field name made lowercase.
defecttype = models.CharField(db_column='defectType', max_length=100, blank=True, null=True) # Field name made lowercase.
creationdate = models.DateTimeField(db_column='creationDate', blank=True, null=True) # Field name made lowercase.
status = models.CharField(max_length=100, blank=True, null=True)
severity = models.CharField(max_length=100, blank=True, null=True)
update_time = models.DateTimeField(blank=True, null=True)
bug_file = models.CharField(max_length=300, blank=True, null=True)
class Meta:
managed = False
db_table = 'bugs'
四、urls.py:
專門用於與視圖函數view.py映射的,如果來了一個請求,就會從這個文件中找到匹配的視圖函數。
在一個網站,比如個人信息存放的頁面:/profile;新聞列表頁存放的頁面路徑是:/list;詳情頁面是:/content
這些信息都是在urls.py配置的;
1. 視圖寫完後,要與URL進行映射,在 urls.py 文件中有一個 urlpatterns 變量,該變量在url文件中是一個url映射列表。
2. 在用戶輸入了某個 url ,請求到我們的網站的時候,django 會在項目的urls.py文件中,遍歷urlpatterns列表來查找對應的處理函數(視圖)。當url有重複的情況則以找到的第一個爲準,成功匹配後,就會執行該url後面的path方法,也就是用戶可以看到的頁面;如果匹配不成功則會報錯。
3. Urlpatterns常用函數:path和url
1. URL嵌套:
在一個項目中,通常不會只有一個app,如果把所有的 app 的 views 中的視圖都放在 urls.py 中進行映射,會讓代碼顯得非常亂。因此 django 給我們提供了一個方法,可以在 app 內部包含自己的 url 匹配規則,而在項目的 urls.py 中再統一包含這個 app 的 urls 。使用這個技術需要藉助 include 函數。
- URL分爲項目URL和app的URL
- 我們一般定義的都會放在app的url裏,然後把整個app的url放到項目的url中進行路由
下面是項目級別的url
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'', include('mysite.urls')),
url(r'^admin/', admin.site.urls),
]
下面是app級別的url:二級路由
from django.conf.urls import url
from django.views import static
from django.conf import settings
from . import views
app_name = 'mysite'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^add-ol-issue$', views.add_ol_issue, name='addolissue'),
url(r'^search$', views.search, name='search'),
url(r'^search2$', views.search2, name='search2'),
url(r'get_project$', views.get_project, name="get_project"),
url(r'^filldata$', views.filldata, name='filldata'),
url(r'delete$', views.delete, name='delete'),
url(r'^edit_online_page$', views.edit_online_page, name='edit_online_page'),
url(r'^tr_filldata$', views.tr_filldata, name='tr_filldata'),
url(r'^upload$', views.import_excel, name='upload'),
url(r'^static/(?P<path>.*)$', static.serve, {'document_root': settings.STATIC_ROOT}, name='static'),
url(r'^version$', views.version, name='version')
]
2.URL映射
假設後端view.py的有filldata函數,其路由流程爲:
# View.py詳情頁面請求數據
def filldata(request):
if request.is_ajax(): # filldata
onlineproblem_id= int(request.POST['IIID'])
content = OnlineProblem.objects.filter(id=onlineproblem_id)
result = serializers.serialize("json", content)
return JsonResponse(result, safe=False)
url函數:
# urls.py詳情頁面請求數據(^:從字符串開頭進行匹配,$:從字符串末尾進行匹配)
from django.conf.urls import url
from django.views import static
from django.conf import settings
from . import views
#從當前路徑導入view,也可以用from app import views(app是自己定義的)
app_name = 'mysite'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^add-ol-issue$', views.add_ol_issue, name='addolissue'),
url(r'^search$', views.search, name='search'),
url(r'^filldata$', views.filldata, name='filldata')]
3.urls.py中urlpatterns中path函數、re_path函數和url函數
django1.x版本的from django.conf.urls import url,include,用url的路由:url()寫的是正則表達式(regex)的路由
Django2.x版本的from django.urls import path, re_path, include用path和re_path路由:path()寫的是非正則路由(route)
(1)django1.x中的url:
函數傳遞了四個參數,兩個必需:regex
和view
,以及兩個可選:kwargs
,和name
。也就是正則表達式和視圖是兩個必填參數。
from django.conf.urls import url
from django.views import static
from django.conf import settings
from . import views
app_name = 'mysite'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^add-ol-issue$', views.add_ol_issue, name='addolissue'),
url(r'^search$', views.search, name='search'),
url(r'^search2$', views.search2, name='search2'),
url(r'get_project$', views.get_project, name="get_project"),
url(r'^filldata$', views.filldata, name='filldata'),
url(r'delete$', views.delete, name='delete'),
url(r'^edit_online_page$', views.edit_online_page, name='edit_online_page'),
url(r'^tr_filldata$', views.tr_filldata, name='tr_filldata'),
url(r'^upload$', views.import_excel, name='upload'),
url(r'^static/(?P<path>.*)$', static.serve, {'document_root': settings.STATIC_ROOT}, name='static'),
url(r'^version$', views.version, name='version')
]
(2)Django2.1的path函數
path()函數 具有四個參數,兩個必須參數:route
和 view
,兩個可選參數:kwargs
和 name
。即路由和視圖是必填參數。
path()的route參數:
例如,URLconf在處理請求https://www.example.com/myapp/時,它會嘗試匹配myapp/。處理請求https://www.example.com/myapp/?page=3 時,也只會嘗試匹配 myapp/。
path()的view參數:
當 Django 找到了一個匹配的準則,就會調用這個特定的視圖函數,並傳入一個HttpRequest對象作爲第一個參數,被“捕獲”的參數以關鍵字參數的形式傳入。
# 項目的url,路徑爲Myproject/urls.py 項目級別的中括號之前有,
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('book/',include("book.urls")),]
# app爲book的url,book/urls.py文件:以後在請求 book 相關的url
的時候都需要加一個 book 的前綴。App級別的中括號之前沒有,
from django.urls import path
from . import views
urlpatterns = [
path('list/',views.book_list),
path('detail/<book_id>/',views.book_detail)]
帶參數的url的入參值,是從view.py後端代碼裏獲取的:
def peopleList(request,book_id)
第一個request是默認的,那麼路徑自動匹配該函數的第二個形參,匹配格式:<int:book_id>,並返回一個正整數或零值。