【Django】快速入門_基本配置

前提

已安裝python3.X

安裝完django

創(chuàng)建項(xiàng)目

#在命令行執(zhí)行
#HelloWorld 項(xiàng)目名稱
django-admin startproject HelloWorld

#進(jìn)入項(xiàng)目
cd HelloWorld

目錄說明

|-- HelloWorld
| |-- init.py #空文件,告訴Python這是一個(gè)Python的包
| |-- asgi.py #一個(gè) ASGI 兼容的 Web 服務(wù)器的入口,以便運(yùn)行你的項(xiàng)目。
| |-- settings.py #該 Django 項(xiàng)目的設(shè)置/配置。
| |-- urls.py #該 Django 項(xiàng)目的 URL 聲明; 一份由 Django 驅(qū)動(dòng)的網(wǎng)站"目錄"。
| -- wsgi.py-- manage.py #一個(gè) WSGI 兼容的 Web 服務(wù)器的入口,以便運(yùn)行你的項(xiàng)目。

運(yùn)行項(xiàng)目

#確保已進(jìn)入HelloWorld目錄下

#多種運(yùn)行項(xiàng)目的方式
python manage.py runserver
# 指定端口
python manage.py runserver 8080
# 任意ip接入
python manage.py runserver 0.0.0.0:8080
# 這里和settings.py的配置ALLOWED_HOSTS = []
# 不一樣的地方在于,這個(gè)是服務(wù)器監(jiān)聽的IP,IP不對(duì)無(wú)法連接到服務(wù);
# ALLOWED_HOSTS是已經(jīng)連接到服務(wù),但連接的IP不在ALLOWED_HOSTS范圍內(nèi)就無(wú)法正常提供服務(wù)

運(yùn)行完項(xiàng)目訪問 127.0.0.1:8000,就能看到一個(gè)綠色的小火箭!

視圖和URL配置

注意import

HelloWorld 目錄新建一個(gè) views.py 文件

#目錄:HelloWorld/HelloWorld/views.py

from django.http import HttpResponse
 
def hello(request):
    return HttpResponse("Hello world ! ")

綁定 URL 與視圖函數(shù)

from django.conf.urls import url
 
from . import views
 
urlpatterns = [
    url(, views.hello),
]

path() 函數(shù)

path(route, view, kwargs=None, name=None)
  • route: 字符串,表示 URL 規(guī)則,與之匹配的 URL 會(huì)執(zhí)行對(duì)應(yīng)的第二個(gè)參數(shù) view。(可用正則表達(dá)式)
  • view: 用于執(zhí)行與正則表達(dá)式匹配的 URL 請(qǐng)求。
  • kwargs: 視圖使用的字典類型的參數(shù)。
  • name: 用來(lái)反向獲取 URL。

route:

views:

  • from . import views導(dǎo)入的
  • views.hello 對(duì)應(yīng)的是views中的一個(gè)函數(shù)

kwargs:

  • 少用到,暫不學(xué)

模板

為什么需要模板?

在上文views的hello中使用 django.http.HttpResponse() 來(lái)輸出 "Hello World!",該方式將數(shù)據(jù)與視圖混合在一起,不符合 Django 的 MVC 思想

模板:模板是一個(gè)文本,用于分離文檔的表現(xiàn)形式和內(nèi)容。

建立模板

在 HelloWorld 目錄底下創(chuàng)建 templates 目錄并建立 runoob.html

項(xiàng)目結(jié)構(gòu)

HelloWorld/
|-- HelloWorld
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- settings.py
|   |-- settings.pyc
|   |-- urls.py
|   |-- urls.pyc
|   |-- views.py
|   |-- views.pyc
|   |-- wsgi.py
|   `-- wsgi.pyc
|-- manage.py
`-- templates
    `-- runoob.html

HelloWorld/templates/runoob.html 文件代碼

<h1>{{ hello }}</h1>

修改HelloWorld/settings.py

修改 TEMPLATES 中的 DIRS 為 [os.path.join(BASE_DIR, 'templates')]

  • 注意導(dǎo)入:import os
...
import os
...
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ...
    },
]
...

修改 views.py

from django.shortcuts import render
 
def runoob(request):
    context          = {}
    context['hello'] = 'Hello World!'
    return render(request, 'runoob.html', context)

#context可換成{"name":views_name}

修改HelloWorld/HelloWorld/urls.py

from django.urls import path
 
from . import views
 
urlpatterns = [
    path('runoob/', views.runoob),
]

模板語(yǔ)法

views中的變量與html中變量“綁定”

view:{"HTML變量名" : "views變量名"}
HTML:{{變量名}}
#html頁(yè)面中
<h1>{{HTML變量名}}</h1>

#在views中
return render(request, 'runoob.html', {"HTML變量名" : "views變量名"})

網(wǎng)頁(yè)導(dǎo)航和頁(yè)腳

使用子模版繼承父模版,減少代碼冗余

父模板

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>base</title>
</head>
<body>
    <h1>Hello World!</h1>
    <p>父模板測(cè)試</p>
    {% block mainbody %}
       <p>base template</p>
    {% endblock %}
</body>
</html>

子模板

{%extends "base.html" %}

  • 繼承了一個(gè)父模板(網(wǎng)頁(yè))

父模板的{% block 名稱%}{% 名稱%}

  • 相當(dāng)于留空位給子模版新增內(nèi)容
  • 標(biāo)簽是可以被繼承者們替換掉的部分
{%extends "base.html" %}
 
{% block mainbody %}
<p>繼承了 base.html 文件</p>
{% endblock %}

模型

參考

Django 模型使用自帶的 ORM。

  • 對(duì)象關(guān)系映射(Object Relational Mapping,簡(jiǎn)稱 ORM )用于實(shí)現(xiàn)面向?qū)ο缶幊陶Z(yǔ)言里不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換。
image.png
# 安裝 mysql 驅(qū)動(dòng)
pip install pymysql

在數(shù)據(jù)庫(kù)軟件中新建數(shù)據(jù)庫(kù)

-- runoob 數(shù)據(jù)庫(kù)名
create database runoob default charset=utf8;  

修改 HelloWorld/HelloWorld/settings.py 中的DATABASES

DATABASES = { 
    'default': 
    { 
        'ENGINE': 'django.db.backends.mysql',    # 數(shù)據(jù)庫(kù)引擎
        'NAME': 'runoob', # 數(shù)據(jù)庫(kù)名稱
        'HOST': '127.0.0.1', # 數(shù)據(jù)庫(kù)地址,本機(jī) ip 地址 127.0.0.1 
        'PORT': 3306, # 端口 
        'USER': 'root',  # 數(shù)據(jù)庫(kù)用戶名
        'PASSWORD': '123456', # 數(shù)據(jù)庫(kù)密碼
    }  
}

告訴 Django 使用 pymysql 模塊連接 mysql 數(shù)據(jù)庫(kù)

# 在與 settings.py 同級(jí)目錄下的 __init__.py 中引入模塊和進(jìn)行配置 
import pymysql
pymysql.install_as_MySQLdb()

定義模型

Django 規(guī)定,如果要使用模型,必須要?jiǎng)?chuàng)建一個(gè) app。

#命令行中輸入
# TestModel與manage.py在同級(jí)目錄下
django-admin.py startapp TestModel

創(chuàng)建表

修改 TestModel/models.py 文件

# models.py
from django.db import models
 
class Test(models.Model):
    name = models.CharField(max_length=20)

類名代表了數(shù)據(jù)庫(kù)表名(Test)

類里面的字段代表數(shù)據(jù)表中的字段(name)

數(shù)據(jù)類型則由CharField(相當(dāng)于varchar)、DateField(相當(dāng)于datetime)

max_length 參數(shù)限定長(zhǎng)度。

告訴django我們安裝的app

在 settings.py 中找到INSTALLED_APPS

  • setting.py在HelloWorld目錄下
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'TestModel',               # 添加此項(xiàng)
)

命令行中運(yùn)行

python manage.py migrate   # 創(chuàng)建表結(jié)構(gòu)

python manage.py makemigrations TestModel  # 讓 Django 知道我們?cè)谖覀兊哪P陀幸恍┳兏?python manage.py migrate TestModel   # 創(chuàng)建表結(jié)構(gòu)
#如果代碼有報(bào)異常,繼續(xù)往下翻。

第二行代碼執(zhí)行后

image.png

第三行代碼執(zhí)行后

image.png

該表結(jié)構(gòu)

Django 會(huì)自動(dòng)添加一個(gè) id 作為主鍵。

image.png

異常

django.db.utils.OperationalError:(1045,"Access denied for user 'root'@'localhost'

  • 確保用戶名和密碼正確后再試一次
    • 可以用命令行測(cè)試數(shù)據(jù)庫(kù)連接
    • 開啟服務(wù):net start 服務(wù)名(例如:mysql5.7)
    • mysql -h 主機(jī)名(ip) -u 用戶名 -P 端口 -p

其他解決方案

數(shù)據(jù)庫(kù)操作

HelloWorld 目錄中添加 testdb.py 文件,并修改 urls.py

#urls.py
from django.urls import path
 
from . import views,testdb
 
urlpatterns = [
    path('runoob/', views.runoob),
    path('testdb/', testdb.testdb),
]
添加數(shù)據(jù)
from django.http import HttpResponse
 
from TestModel.models import Test
 
# 數(shù)據(jù)庫(kù)操作
def testdb(request):
    test1 = Test(name='runoob')
    test1.save()
    return HttpResponse("<p>數(shù)據(jù)添加成功!</p>")

啟動(dòng)服務(wù)器并訪問

python manage.py runserver #啟動(dòng)服務(wù)器

#訪問 http://127.0.0.1:8000/testdb/
#看到頁(yè)面輸出:數(shù)據(jù)添加成功

查看數(shù)據(jù)庫(kù)

image.png
獲取數(shù)據(jù)、刪除、修改

參考

#獲取
# 通過objects這個(gè)模型管理器的all()獲得所有數(shù)據(jù)行,相當(dāng)于SQL中的SELECT * FROM
list = Test.objects.all()

# filter相當(dāng)于SQL中的WHERE,可設(shè)置條件過濾結(jié)果
response2 = Test.objects.filter(id=1) 

# 獲取單個(gè)對(duì)象
response3 = Test.objects.get(id=1) 

# 限制返回的數(shù)據(jù) 相當(dāng)于 SQL 中的 OFFSET 0 LIMIT 2;(分頁(yè))
Test.objects.order_by('name')[0:2]

#數(shù)據(jù)排序
Test.objects.order_by("id")

# 上面的方法可以連鎖使用
Test.objects.filter(name="runoob").order_by("id")
#修改
#save() 或 update():
# 修改其中一個(gè)id=1的name字段,再save,相當(dāng)于SQL中的UPDATE
test1 = Test.objects.get(id=1)
test1.name = 'Google'
test1.save()

# 另外一種方式
Test.objects.filter(id=1).update(name='Google')

# 修改所有的列
Test.objects.all().update(name='Google')
#刪除
# 刪除id=1的數(shù)據(jù)
test1 = Test.objects.get(id=1)
test1.delete()

# 另外一種方式
Test.objects.filter(id=1).delete()

# 刪除所有數(shù)據(jù)
Test.objects.all().delete()

異常

刪除數(shù)據(jù)庫(kù)表后無(wú)法更新

問題:修改模型后無(wú)法更新數(shù)據(jù)庫(kù)表結(jié)構(gòu),刪除后再執(zhí)行命令也不行。參考

解決:

  1. 刪除app/migrations/目錄下 “_pycache_” 文件

  2. 刪除app下面目錄migrations下面除了init.py其他的所有文件

  3. 刪除對(duì)應(yīng)數(shù)據(jù)庫(kù)中django_migrations表中app名稱所在的列

    (或者delete from django_migrations where app=‘yourappname’;),解決無(wú)法生成表

表單

HTML表單是網(wǎng)站交互性的經(jīng)典方式。

HTTP協(xié)議以"請(qǐng)求-回復(fù)"的方式工作。

  • 客戶發(fā)送請(qǐng)求時(shí),可以在請(qǐng)求中附加數(shù)據(jù)。
  • 服務(wù)器通過解析請(qǐng)求,就可以獲得客戶傳來(lái)的數(shù)據(jù),并根據(jù)URL來(lái)提供特定的服務(wù)。

GET

創(chuàng)建一個(gè) search.py 文件,用于接收用戶的請(qǐng)求

#/HelloWorld/HelloWorld/search.py 文件

from django.http import HttpResponse
from django.shortcuts import render

#表單
def search_form(request):
    return render(request,'search_form.html')

#接收請(qǐng)求數(shù)據(jù)
def search(request):
    request.encoding='utf-8'
    if('q' in request.GET and request.GET['q']):
        message = '您搜索的內(nèi)容為:' + request.GET['q']
    else:
        message = '您提交了空表單'
    return HttpResponse(message)

模板目錄 templates 中添加 search_form.html 表單

#/HelloWorld/templates/search_form.html 文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form_test</title>
</head>
<body>
    <form action="/search/" method="GET">
        <input type="text" name="q">
        <input type="submit" value="搜索">
    </form>
</body>
</html>

urls.py 規(guī)則 添加以下代碼

使用url能匹配正則表達(dá)式(path好像不行)

...
from django.conf.urls import url

urlpatterns = [
    ...,
    url(r'^search-form/$',search.search_form),
    url(r'^search/$',search.search)
]

訪問 http://127.0.0.1:8000/search-form/,搜索后提交即可看到效果

GET請(qǐng)求 視圖顯示和請(qǐng)求處理分成兩個(gè)函數(shù)處理。

POST

提交數(shù)據(jù)時(shí)更常用POST方法。

  • 一個(gè)URL和處理函數(shù),同時(shí)顯示視圖和處理請(qǐng)求。

Request對(duì)象

表單form通過HTTP POST方法提交請(qǐng)求,但是表單中可以沒有數(shù)據(jù)。

因此,不能使用語(yǔ)句if request.POST來(lái)判斷是否使用HTTP POST方法;

應(yīng)該使用if request.method == "POST"

參考1

參考2

參考3

路由

Django不會(huì)匹配域名和協(xié)議

舉例:

請(qǐng)求:訪問http://127.0.0.1:8000/polls/34/

Django項(xiàng)目到urls中順序進(jìn)行正則匹配/polls/34/,匹配到polls/,就切掉文本"polls/",剩余文本"34/"繼續(xù)進(jìn)行匹配

  • path('polls/',include('polls.urls'))
  • path('<int:question_id>/', views.detail, name='detail')

匹配到了views.detail

得到參數(shù)question_id=34<int:question_id> 匹配生成。

  • 使用尖括號(hào)“捕獲”這部分 URL,且以關(guān)鍵字參數(shù)的形式發(fā)送給視圖函數(shù)。
  • 上述字符串的 :question_id> 部分定義了將被用于區(qū)分匹配模式的變量名
  • int: 則是一個(gè)轉(zhuǎn)換器決定了應(yīng)該以什么變量類型匹配這部分的 URL 路徑。

路由簡(jiǎn)單的來(lái)說就是根據(jù)用戶請(qǐng)求的 URL 鏈接來(lái)判斷對(duì)應(yīng)的處理程序,并返回處理結(jié)果,

  • URL 與 Django 的視圖建立映射關(guān)系。

Django 路由在 urls.py 配置,urls.py 中的每一條配置對(duì)應(yīng)相應(yīng)的處理方法。

Django 不同版本 urls.py 配置有點(diǎn)不一樣

Django1.1.x 版本

url() 方法:普通路徑和正則路徑均可使用,需要自己手動(dòng)添加正則首位限制符號(hào)。

from django.conf.urls import url # 用 url 需要引入 

urlpatterns = [ 
    url(r'^admin/$', admin.site.urls), 
    url(r'^index/$', views.index), # 普通路徑 
    url(r'^articles/([0-9]{4})/$', views.articles), # 正則路徑 
]

Django 2.2.x 之后

  • path:用于普通路徑,不需要自己手動(dòng)添加正則首位限制符號(hào),底層已經(jīng)添加。
  • re_path:用于正則路徑,需要自己手動(dòng)添加正則首位限制符號(hào)。
from django.urls import re_path # 用re_path 需要引入 
urlpatterns = [ 
    path('admin/', admin.site.urls), 
    path('index/', views.index), # 普通路徑 
    re_path(r'^articles/([0-9]{4})/$', views.articles), # 正則路徑 
]

總結(jié):Django1.1.x 版本中的 url 和 Django 2.2.x 版本中的 re_path 用法相同。

分組

參考

正則還有分組的概念,但是在Django中把分組分為兩種:

  • 無(wú)名分組
  • 有名分組

無(wú)名分組

無(wú)名分組:普通的正則匹配中加上()

作用:在后端的views上,會(huì)得到一個(gè)分組的參數(shù)

  • 訪問views.login函數(shù)(下方)的參數(shù)除了request,還需要添加一個(gè)參數(shù)(名字隨意)
  • 要設(shè)置幾個(gè)參數(shù)就要多幾個(gè)分組

以下代碼訪問:login/2222,那么xxx的值為2222

#urls.py
urlpatterns = [
 url(r'^login/([0-9]{4})$',views.login),
]

#views.py
def login(request,xxx):
    print(xxx)

舉例參考

#search2.py
def divede_group_year(request,year):
    return HttpResponse('您的選擇是:%s' % year)
def divede_group_month(request,year,month):
    return HttpResponse('選擇的月份是:%s-%s' %(year,month))

#urls.py
from django.urls import path,re_path
...

urlpatterns = [
    ...,
    # 記得添加結(jié)束標(biāo)簽 $
    re_path(r'^divede-group/([0-9]{4})/$',search2.divede_group_year),
    re_path(r'^divede-group/([0-9]{4})/([0-9]{2})/$',search2.divede_group_month)
]
image.png
image.png

有名分組

有名分組: 有名分組其實(shí)就是在無(wú)名的分組的基礎(chǔ)上加上了名字

語(yǔ)法為:(?P<名字> 正則表達(dá)式)

#urls.py
...,

urlpatterns = [
    ...,
 url(r'^login/(?P<year>[0-9]{4})$',views.login),
]

#views.py
...,
def login(request,year):
     print(year)

舉例

#search2.py
from django.http import HttpResponse
def divede_group_name(request,name):
    return HttpResponse('有名分組:%s' %(name))

#urls.py
from . import search2
re_path(r'^divede-group/(?P<name>[a-z]{4})/$',search2.divede_group_name)
image.png

視圖函數(shù)的參數(shù)name 要和有名參數(shù)的名字name一致,否則會(huì)報(bào)錯(cuò)!

注意:官方規(guī)定,有名分組和無(wú)名分組不能一起使用!

路由分發(fā)(include)

問題:

  • 項(xiàng)目里多個(gè)app目錄共用一個(gè) urls 容易造成混淆
  • 后期維護(hù)不方便

解決:

  • 使用路由分發(fā)(include),讓每個(gè)app目錄都單獨(dú)擁有自己的 urls。

步驟:

  • 1、在每個(gè) app 目錄里都創(chuàng)建一個(gè) urls.py 文件。
  • 2、在項(xiàng)目名稱目錄下的 urls 文件里,統(tǒng)一將路徑分發(fā)給各個(gè) app 目錄。
舉例:

有兩個(gè)app,都有index.html頁(yè)面

  • 如果在項(xiàng)目的urls中配置,則會(huì)造成混淆
  • 且如果有太多的url,則維護(hù)十分難

所以應(yīng)該把各種的url分給各自去管理

#路由 未分發(fā)
#項(xiàng)目主目錄下的urls.py
urlpatterns = [
    url(r'^app-one/index/$',views.index),
    url(r'^app-two/index/$',views.index)
]

新建兩個(gè)app

# 語(yǔ)法:python manage.py startapp <app名稱>
# 命令行中運(yùn)行
python manage.py startapp app01
python manage.py startapp app02

app1目錄下

1.views文件

from django.http import HttpResponse

def index(request):
    return HttpResponse('app01的index頁(yè)面!')

2.新建urls.py文件

from . import views
from django.conf.urls import url #沒有引入會(huì)報(bào)錯(cuò):NameError: name 'url' is not defined django
urlpatterns = [
    url(r'^index/$',views.index)
]

app2目錄下

1.views文件

from django.http import HttpResponse

def index(request):
    return HttpResponse('app2:index!')

2.新建urls.py文件

from . import views
from django.conf.urls import url

urlpatterns = [
    url(r'^index/$',views.index)
]

項(xiàng)目主目錄下的urls.py

urlpatterns = [
    url(r'^app-one/',include('app01.urls')),
    url(r'^app-two/',include('app02.urls'))
]

訪問

注意訪問路徑:

  • app-one/index/
  • 對(duì)照上面的urls.py文件,就能理解路由轉(zhuǎn)發(fā)了!

app01

運(yùn)行項(xiàng)目:python manage.py runserver

image.png

app02

image.png

反向解析

目的:解耦

  • 路由層的 url 發(fā)生變化,就需要去更改對(duì)應(yīng)的視圖層和模板層的 url,不便維護(hù)

反向解析

  • 當(dāng)路由層 url 發(fā)生改變,在視圖層和模板層動(dòng)態(tài)反向解析出更改后的 url,免去修改的操作。
  • 一般用在模板中的超鏈接及視圖中的重定向

問題舉例

#urls.py 中的一條url
...
url(r'^login/$',views.login)
...
#html頁(yè)面中的提交表單
<form action="/login/" method="P=post">
    ...
</form>

當(dāng)更改路由中的url時(shí),需要在html頁(yè)面也做相應(yīng)的更改!

解耦目的:只更改路由中的url,html中會(huì)自動(dòng)做出更改,我們無(wú)需去改變!

反向解析

方法:給路由器起別名

應(yīng)用:

舉例參考

1.普通路徑:name="路由別名

重定向:

  • redirect(reverse("login"))

超鏈接:

  • <form action="{% url 'login' %}" method="post">

2.正則路徑:無(wú)名分組

re_path(r"^login/([0-9]{2})/$", views.login, name="login")

重定向:

  • reverse("路由別名",args=(符合正則匹配的參數(shù),))
    • redirect(reverse("login",args=(10,)))

超鏈接:

  • {% url "路由別名" 符合正則匹配的參數(shù) %}
    • {% url 'login' 10 %}

3.正則路徑:有名分組

re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")

重定向:

  • reverse("路由別名",kwargs={"分組名":符合正則匹配的參數(shù)})
    • redirect(reverse("login",kwargs={"year":3333}))

超鏈接:

  • {% url "路由別名" 分組名=符合正則匹配的參數(shù) %}
    • {% url 'login' year=3333 %}

命名空間

命名空間(英語(yǔ):Namespace)是表示標(biāo)識(shí)符可見范圍。

一個(gè)標(biāo)識(shí)符可在多個(gè)命名空間中定義,它在不同命名空間中的含義是互不相干的。

一個(gè)新的命名空間中可定義任何標(biāo)識(shí)符,它們不會(huì)與任何重復(fù)的標(biāo)識(shí)符發(fā)生沖突,因?yàn)橹貜?fù)的定義都處于其它命名空間中。

存在問題:路由別名 name 沒有作用域,Django 在反向解析 URL 時(shí),會(huì)在項(xiàng)目全局順序搜索,當(dāng)查找到第一個(gè)路由別名 name 指定 URL 時(shí),立即返回。當(dāng)在不同的 app 目錄下的urls 中定義相同的路由別名 name 時(shí),可能會(huì)導(dǎo)致 URL 反向解析錯(cuò)誤。

解決:使用命名空間。

普通路徑

方式一:

#主目錄下的urls
urlpatterns = [
    path('admin/', admin.site.urls),
    path('polls/',include('polls.urls'))
]
# polls中的urls.py
from django.urls import path
from . import views

app_name = 'polls' #命名空間
urlpatterns = [
    ...
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    ...
]
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

方式二:

定義命名空間(include 里面是一個(gè)元組)

include(("app名稱:urls","app名稱"))

實(shí)例

path("app01/", include(("app01.urls","app01"))) 
path("app01/", include(("app02.urls","app02")))

起別名

path("login/", views.login, name="login")

調(diào)用

#重定向
redirect(reverse("app01:login")
         
#超鏈接
{% url "app名稱:路由別名" %}

視圖

每個(gè)視圖必須要做的只有兩件事:

  • 返回一個(gè)包含被請(qǐng)求頁(yè)面內(nèi)容的 HttpResponse 對(duì)象
  • 或者拋出一個(gè)異常,比如 Http404 。

基于類的視圖

Admin 管理工具

介紹

Django 提供了基于 web 的管理工具。

Django 自動(dòng)管理工具是 django.contrib 的一部分。

在項(xiàng)目的 settings.py 中的 INSTALLED_APPS 可以看到

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)

django.contrib是一套龐大的功能集,它是Django基本代碼的組成部分。

激活管理工具

在生成項(xiàng)目時(shí)會(huì)在 urls.py 中自動(dòng)設(shè)置好,我們只需去掉注釋即可。

配置如下

# urls.py
from django.conf.urls import url
from django.contrib import admin
 
urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

使用管理工具

創(chuàng)建超級(jí)用戶

# python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: 
Password:admin
Password (again):
Superuser created successfully.
  1. 創(chuàng)建模型(model)
  2. 修改admin.py
  3. 告知Django模型有更改
  4. 創(chuàng)建表

之前在 TestModel 中已經(jīng)創(chuàng)建了模型 Test 。修改 TestModel/admin.py:

from django.contrib import admin
from TestModel.models import Test
 
# Register your models here.
admin.site.register(Test)

復(fù)雜模型

TestModel/models.py 中增加一個(gè)更復(fù)雜的數(shù)據(jù)模型

from django.db import models

# Create your models here.
class Test(models.Model):
    name = models.CharField(max_length=20)

class Contact(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField(default=0)
    email = models.EmailField()
    def __unicode__(self):
        return self.name

class Tag(models.Model):
    concate = models.ForeignKey(Contact,on_delete=models.CASCADE)
    name = models.CharField(max_length=50)
    def __unicode__(self):
        return self.name

TestModel/admin.py中修改

from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
admin.site.register([Test,Contact,Tag])

刷新 http://127.0.0.1:8000/admin/ 頁(yè)面

image.png

現(xiàn)在只是有了Concate和Tag模型,在數(shù)據(jù)庫(kù)中還沒有對(duì)應(yīng)的表

(Test是文章前面建的)

image.png

使用以下命令創(chuàng)建表結(jié)構(gòu)

python manage.py makemigrations TestModel  # 讓 Django 知道我們?cè)谖覀兊哪P陀幸恍┳兏?python manage.py migrate TestModel   # 創(chuàng)建表結(jié)構(gòu)

第一條命令執(zhí)行完,多了一個(gè)文件

image.png

第二條命令執(zhí)行完,創(chuàng)建了對(duì)應(yīng)的表

(有關(guān)數(shù)據(jù)庫(kù)連接請(qǐng)看“模型”)

image.png

自定義admin界面

自定義表單

1.把Age隱藏起來(lái)
image.png

修改 TestModel/admin.py:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
class ContactAdmin(admin.ModelAdmin):  #新增代碼
    fields = ('name','email')         #新增代碼

admin.site.register(Contact,ContactAdmin) #新增代碼
admin.site.register([Test,Tag])          #刪除",Contact"

代碼說明

定義了一個(gè) ContactAdmin 類,用以說明管理頁(yè)面的顯示格式。

  • fields 屬性定義了要顯示的字段
  • 該類對(duì)應(yīng)的是 Contact 數(shù)據(jù)模型,我們?cè)谧?cè)的時(shí)候,需要將它們一起注冊(cè)

刷新后顯示效果如下

image.png
2.將輸入欄分塊,每個(gè)欄也可以定義自己的格式。

注意字母拼寫不要錯(cuò)誤!??!

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
 
# Register your models here.
class ContactAdmin(admin.ModelAdmin):
    fieldsets = (
        ['Main',{
            'fields':('name','email'),
        }],
        ['Advance',{
            'classes': ('collapse',), # CSS
            'fields': ('age',),
        }]
    )

admin.site.register(Contact, ContactAdmin)
admin.site.register([Test, Tag])

刷新頁(yè)面

image.png

點(diǎn)擊“Show”

image.png

說明

上面的欄目分為了 Main 和 Advance 兩部分。

classes 說明它所在的部分的 CSS 格式。這里讓 Advance 部分隱藏

內(nèi)聯(lián)(Inline)顯示

上面的 Contact 是 Tag 的外部鍵,所以有外部參考的關(guān)系。

問題:在默認(rèn)的頁(yè)面顯示中,將兩者分離開來(lái),無(wú)法體現(xiàn)出兩者的從屬關(guān)系。

解決:可以使用內(nèi)聯(lián)顯示,讓 Tag 附加在 Contact 的編輯頁(yè)面上顯示。

修改TestModel/admin.py

from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
class TagInline(admin.TabularInline): #新增代碼
    model = Tag                     #新增代碼

class ContactAdmin(admin.ModelAdmin):
    inlines = [TagInline] #Inline   #修改代碼
    fieldsets = (
    ['Main',{
        'fields':('name','email'),
    }],
    ['Advance',{
        'classes':('cpllapse',), #CSS
        'fields':('age',),
    }]
)
        

admin.site.register(Contact,ContactAdmin)
admin.site.register([Test])         #修改代碼

刷新顯示

image.png

列表頁(yè)的顯示

在 Contact 輸入數(shù)條記錄后,Contact 的列表頁(yè)看起來(lái)如下

image.png

目的:在列表中顯示更多的欄目

  • 在 ContactAdmin 中增加 list_display 屬性
from django.contrib import admin
from TestModel.models import Test,Contact,Tag

# Register your models here.
class TagInline(admin.TabularInline):
    model = Tag

class ContactAdmin(admin.ModelAdmin):
    list_display = ('name','age','email') #新增list_display屬性
    inlines = [TagInline] #Inline
    fieldsets = (
    ['Main',{
        'fields':('name','email'),
    }],
    ['Advance',{
        'classes':('cpllapse',), #CSS
        'fields':('age',),
    }]
)
        

admin.site.register(Contact,ContactAdmin)
admin.site.register([Test])

刷新顯示

image.png

app

一個(gè)項(xiàng)目中可以創(chuàng)建很多個(gè)app

app可以用路由分發(fā)解決url沖突

使用命名空間也可以減少模板沖突等等

應(yīng)用1

image.png

qyvxtest:項(xiàng)目名

charlist:新建的app

app可以成為絕對(duì)路徑的引入,解決的導(dǎo)入模塊時(shí)的問題

例如:在一個(gè)項(xiàng)目中,新建了一個(gè)app,在該app的views中

from . import models

#異常
#RuntimeError: Model class chatlist.models.User doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS

在setting中

INSTALLED_APPS = [
    ...,
    'chatlist',
]

則在該app的view中可以

from . import models
#或者
from chatlist import models
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容