您好,登錄后才能下訂單哦!
使用Django2怎么開發一個Web項目?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
新建 Django 項目
# 建立虛擬環境 C:\Workspace\django λ python -m venv venv # 激活虛擬環境 C:\Workspace\django λ .\venv\Scripts\activate.bat (venv) λ # 安裝Django C:\Workspace\django (venv) λ pip install Django Looking in indexes: https://mirrors.aliyun.com/pypi/simple/ Collecting Django Using cached https://mirrors.aliyun.com/pypi/packages/fd/9a/0c028ea0fe4f5803dda1a7afabeed958d0c8b79b0fe762ffbf728db3b90d/Django-2.1.4-py3-none-any.whl Collecting pytz (from Django) Using cached https://mirrors.aliyun.com/pypi/packages/f8/0e/2365ddc010afb3d79147f1dd544e5ee24bf4ece58ab99b16fbb465ce6dc0/pytz-2018.7-py2.py3-none-any.whl Installing collected packages: pytz, Django Successfully installed Django-2.1.4 pytz-2018.7 # 進入虛擬環境目錄,新建一個Django項目 C:\Workspace\django (venv) λ django-admin startproject mysite C:\Workspace\django (venv) λ ls mysite/ venv/ # 進入新建的Django項目,建立一個應用 C:\Workspace\django (venv) λ cd mysite\ C:\Workspace\django\mysite (venv) λ python manage.py startapp demo C:\Workspace\django\mysite (venv) λ ls demo/ manage.py* mysite/ # 同步數據庫 C:\Workspace\django\mysite (venv) λ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying sessions.0001_initial... OK # 啟動開發服務 (venv) λ python manage.py runserver 8080 Performing system checks... System check identified no issues (0 silenced). January 03, 2019 - 21:31:48 Django version 2.1.4, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8080/ Quit the server with CTRL-BREAK. # 返回uinika虛擬環境目錄,并將當前虛擬環境的依賴導入至requirements.txt C:\Workspace\django\mysite (venv) λ cd .. C:\Workspace\django (venv) λ pip freeze > requirements.txt C:\Workspace\django (venv) λ ls mysite/ requirements.txt venv/
通過 django-admin startproject
命令創建的外部 mysite/
目錄是 Web 項目的容器,而 manage.py
文件是用于與 Django 項目交互的命令行工具,更多的使用方式可以參閱 django-admin 文檔 。。
mysite/ manage.py mysite/ __init__.py settings.py urls.py wsgi.py
內部嵌套的 mysite/
目錄是用于放置項目中具體的 Python 包,它的名稱是您需要用來導入其中任何內容的 Python 包名稱,例如 mysite.urls
。
mysite/__init__.py
: 空文件,用于提示系統將當前目錄識別為一個 Python 包。
mysite/settings.py
: Django 項目的配置文件,更多配置請查閱 Django settings 。
mysite/urls.py
: 當前 Django 項目的 URL 聲明,更多內容請參閱 URL dispatcher 。
mysite/wsgi.py
: 兼容 WSGI 規范的當前項目入口點,更多細節可以閱讀 如果使用 WSGI 進行部署 。
建立 mysite
項目之后,上面的命令行還通過了 py manage.py startapp
建立了一個 demo/
應用目錄,Django 當中一個項目( mysite
)可以擁有多個應用( demo
), demo/
目錄下的文件結構如下:
demo/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py
請求與響應
首先進入 Python 虛擬環境并進入 mysite
目錄后,執行如下命令:
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py startapp polls
新建一個 polls
應用之后,打開該目錄下的 polls/views.py
源碼文件,輸入以下代碼:
from django.http import HttpResponse def index(request): return HttpResponse("你好,這是一個投票應用!")
接下來,我們需要將上面修改的視圖文件 views.py
映射到一個 URL,先在 polls/
目錄下新建一個 urls.py
文件,然后鍵入下面這段代碼:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
最后,將上面定義的應用的 URL 聲明文件 polls/urls.py
包含至項目的 mysite/urls.py
當中,
from django.contrib import admin from django.urls import include, path urlpatterns = [ path('polls/', include('polls.urls')), path('admin/', admin.site.urls), ]
上面代碼中出現的 include()
函數主要用于引入其它 URL 配置文件,這樣我們就可以通過 http://localhost:8080/polls/
路徑訪問到如下信息了:
模型和管理頁面
mysite/settings.py
文件包含了項目的基本配置,該文件通過如下聲明默認使用 Django 內置的 SQLite 作為項目數據庫。
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
如果使用其它數據庫,則可以將配置書寫為下面的格式:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 數據庫引擎名稱 'NAME': 'db', # 數據庫連接名稱 'USER': 'uinika', # 數據庫連接用戶名 'PASSWORD': 'test', # 數據庫連接密碼 'HOST': 'localhost', # 數據庫主機地址 'PORT': '3306', # 數據庫端口 } }
其中 ENGINE
屬性可以根據項目所使用數據庫的不同而選擇如下值:
SQLite:django.db.backends.sqlite3
MySQL:django.db.backends.mysql
PostgreSQL:django.db.backends.postgresql
Oracle:django.db.backends.oracle
接下來繼續修改 mysite/settings.py
,設置 TIME_ZONE
屬性為項目使用國家的時區。
LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Chongqing'
mysite/settings.py
文件頭部的 INSTALLED_APPS
屬性定義了當前項目使用的應用程序。
INSTALLED_APPS = [ 'django.contrib.admin', # 管理員站點 'django.contrib.auth', # 認證授權系統 'django.contrib.contenttypes', # 內容類型框架 'django.contrib.sessions', # 會話框架 'django.contrib.messages', # 消息框架 'django.contrib.staticfiles', # 靜態文件管理 ]
在前面命令行中執行的 python manage.py migrate
命令會檢查 INSTALLED_APPS
屬性的設置,并為其中的每個應用創建所需的數據表,實際上 migrate
命令只會為對 INSTALLED_APPS
里聲明了的應用進行數據庫遷移 。
了解項目配置文件的一些設置之后,現在來編輯 polls/models.py
文件新建 Question(問題)
和 Choice(選項)
兩個數據模型:
from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)
每個自定義模型都是 django.db.models.Model
的子類,模型里的類變量都表示一個數據庫字段,每個字段實質都是 Field
類的實例。注意在 Choice
使用了 ForeignKey
屬性定義了一個與 Question
的外鍵關聯關系,Django 支持所有常用的多對一、多對多和一對一數據庫關系。
數據庫模型建立完成之后,由于 PollsConfig
類位于 polls/apps.py
文件當中,所以其對應的點式路徑為 polls.apps.PollsConfig
,現在我們需要將該路徑添加至 mysite/settings.py
文件的 INSTALLED_APPS
屬性:
INSTALLED_APPS = [ 'polls.apps.PollsConfig', # 添加PollsConfig 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
通過 manage.py
提供的 makemigrations
命令,將模型的修改遷移到 SQLite 數據庫當中。
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py makemigrations polls Migrations for 'polls': polls\migrations\0001_initial.py - Create model Choice - Create model Question - Add field question to choice
我們還可以通過 manage.py
提供的 sqlmigrate
命令,查看數據遷移過程中執行了哪些 SQL 語句,該命令并不會實質性執行 Django 模型到數據庫的遷移任務。
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py sqlmigrate polls 0001 BEGIN; -- -- Create model Choice -- CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "v otes" integer NOT NULL); -- -- Create model Question -- CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL , "pub_date" datetime NOT NULL); -- -- Add field question to choice -- ALTER TABLE "polls_choice" RENAME TO "polls_choice__old"; CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "v otes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERR ED); INSERT INTO "polls_choice" ("id", "choice_text", "votes", "question_id") SELECT "id", "choice_text", "votes", NULL FR OM "polls_choice__old"; DROP TABLE "polls_choice__old"; CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id"); COMMIT;
Django 模型的數據庫主鍵 ID 會被自動創建, 并會在外鍵字段名稱后追加 _id
字符串作為后綴。
接下來運行 manage.py
提供的 migrate
命令,在根據新定義的模型創建相應的數據庫表。
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying polls.0001_initial... OK
為了便于在版本管理系統提交遷移數據,Django 將模型的修改分別獨立為 生成 和 應用 兩個命令,因此修改 Django 模型會涉及如下 3 個步驟:
編輯models.py文件修改模型。
運行python manage.py makemigrations為模型的改變生成遷移文件。
運行python manage.py migrate來應用數據庫遷移。
完成上述 Django 模型與數據庫的同步之后,接下來可以通過 manage.py
提供的 shell
命令,在命令行工具內運行 Django 提供的交互式 API。
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py shell Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from polls.models import Choice, Question >>> Question.objects.all() <QuerySet []> >>> from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) >>> q.save() >>> q.id 1 >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2019, 1, 4, 9, 10, 1, 955820, tzinfo=<UTC>) >>> q.question_text = "What's up?" >>> q.save() >>> Question.objects.all() <QuerySet [<Question: Question object (1)>]>
上面命令行執行結果中的 <Question: Question object (1)>
對于實際開發沒有意義,因此可以考慮為上面建立的 Django 模型增加 __str__()
方法直接打印模型對象的屬性數據。為了便于進一步測試,這里還為 Question
類添加一個自定義的 was_published_recently()
方法:
import datetime from django.db import models from django.utils import timezone class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') # 自定義was_published_recently()方法 def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1) # 添加__str__()方法 def __str__(self): return self.question_text class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) # 添加__str__()方法 def __str__(self): return self.choice_text
完成修改工作之后,再一次運行 python manage.py shell
命令:
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py shell Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from polls.models import Choice, Question >>> Question.objects.all() <QuerySet [<Question: What's up?>]> >>> Question.objects.filter(id=1) <QuerySet [<Question: What's up?>]> >>> Question.objects.filter(question_text__startswith='What') <QuerySet [<Question: What's up?>]> >>> from django.utils import timezone >>> current_year = timezone.now().year >>> Question.objects.get(pub_date__year=current_year) <Question: What's up?> >>> Question.objects.get(id=2) Traceback (most recent call last): File "<console>", line 1, in <module> File "C:\Workspace\django\venv\lib\site-packages\django\db\models\manager.py", line 82, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "C:\Workspace\django\venv\lib\site-packages\django\db\models\query.py", line 399, in get self.model._meta.object_name polls.models.Question.DoesNotExist: Question matching query does not exist. >>> Question.objects.get(pk=1) <Question: What's up?> >>> q = Question.objects.get(pk=1) >>> q.was_published_recently() True >>> q = Question.objects.get(pk=1) >>> q.choice_set.all() <QuerySet []> >>> q.choice_set.create(choice_text='Not much', votes=0) <Choice: Not much> >>> q.choice_set.create(choice_text='The sky', votes=0) <Choice: The sky> >>> c = q.choice_set.create(choice_text='Just hacking again', votes=0) >>> c.question <Question: What's up?> >>> q.choice_set.all() <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> >>> q.choice_set.count() 3 >>> Choice.objects.filter(question__pub_date__year=current_year) <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> >>> c = q.choice_set.filter(choice_text__startswith='Just hacking') >>> c.delete() (1, {'polls.Choice': 1})
管理站點
Django 能夠根據模型自動創建后臺管理界面, 這里我們執行 manage.py
提供的 createsuperuser
命令創建一個管理用戶:
C:\Workspace\django\mysite (master -> origin) (venv) λ python manage.py createsuperuser Username (leave blank to use 'zhenghang'): hank Email address: uinika@outlook.com Password: ******** Password (again): ******** Superuser created successfully.
啟動 Django 服務之后,就可以通過 URL 地址 http://localhost:8080/admin/login
并使用上面新建的用戶名和密碼進行登陸管理操作:
登陸后默認只能對權限相關的 User
和 Group
進行管理,如果我們需要將 Question
數據模型納入管理,那么必須要在 polls/admin.py
文件對其進行注冊。
from django.contrib import admin from .models import Question admin.site.register(Question)
完成注冊之后,刷新管理站點頁面即可查看到 Question
管理選項:
視圖與模板
Django 使用 URLconfs
配置將 URL 與視圖關聯,即將 URL 映射至視圖,下面我們將向 polls/views.py
文件添加一些能夠接收參數的視圖:
from django.http import HttpResponse def index(request): return HttpResponse("你好,這是一個投票應用!") def detail(request, question_id): return HttpResponse("你正在查看問題 %s 。" % question_id) def results(request, question_id): response = "你看到的是問題 %s 的結果。" return HttpResponse(response % question_id) def vote(request, question_id): return HttpResponse("你正在對問題 %s 進行投票。" % question_id)
然后將這些新的視圖添加至 polls.urls
模塊:
from django.urls import path from . import views urlpatterns = [ # 訪問 http://localhost:8080/polls/ path('', views.index, name='index'), # 訪問 http://localhost:8080/polls/5/ path('<int:question_id>/', views.detail, name='detail'), # 訪問 http://localhost:8080/polls/5/results/ path('<int:question_id>/results/', views.results, name='results'), # 訪問 http://localhost:8080/polls/5/vote/ path('<int:question_id>/vote/', views.vote, name='vote'), ]
Django 的每個視圖只會完成兩個任務:第 1 是返回一個包含被請求頁面內容的 HttpResponse
對象,或者拋出一個 Http404
這樣的異常。這里為了展示數據庫里按照發布日期排序的最近五個投票問題,我們再向 polls/views.py
代碼文件的 index()
函數添加如下內容:
from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output)
這樣直接將數據庫查詢結果輸出到頁面的方式并不優雅,實際開發環境當中我們通常會使用模板頁面來展示數據,首先在 polls
應用目錄下創建一個用來存放模板文件的 templates
目錄。由于站點配置文件 mysite/settings.py
里 TEMPLATES
屬性的默認設置,能夠讓 Django 在每個 INSTALLED_APPS
文件夾中自動尋找 templates
子目錄,從而正確定位出模板的位置。
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], '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', ], }, }, ]
接下來繼續在 templates
下面新建一個 polls
目錄,然后在里邊放置一個 index.html
文件,此時通過 URL 地址 http://localhost:8080/polls/
就可以訪問到這個模板文件,模板文件會將按照發布日期排序了的 Question
列表 latest_question_list
放置到 HttpResponse
上下文,并在 polls/index.html
模板當中完成數據綁定。
from django.http import HttpResponse from django.template import loader from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request))
事實上,通過使用 render()
方法,Django 能夠以更加簡化的方式完成載入模板、填充上下文、返回 HttpResponse 對象這一系列步驟:
from django.shortcuts import render from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {'latest_question_list': latest_question_list} return render(request, 'polls/index.html', context)
接下來處理投票詳情頁面,這里會有一個新原則,即如果指定 ID
所對應的 Question
不存在,那么視圖就會拋出一個 Http404
異常。在 polls/views.py
添加如下代碼,
from django.http import Http404 from django.shortcuts import render from .models import Question def detail(request, question_id): try: question = Question.objects.get(pk=question_id) except Question.DoesNotExist: raise Http404("問題不存在!") return render(request, 'polls/detail.html', {'question': qu
然后暫時向 polls/templates/polls/detail.html
添加一行簡單的 代碼便于測試上面的代碼。
Django 提供了諸如 get_object_or_404()
、 get_list_or_404()
這樣的快捷函數語法糖來解決 Http404
判斷的問題,因而上一步的代碼依然可以進一步簡化為下面這樣:
from django.shortcuts import get_object_or_404, render from .models import Question def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question})
讓我們進一步完善polls/templates/polls/detail.html,填充完整的視圖代碼:
<h2>{{ question.question_text }}</h2> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul>
通過在模板代碼中使用.符號來訪問變量屬性,例如對于上面代碼中的, Django 首先會嘗試對question對象使用字典查找(既obj.get(str)),如果失敗再嘗試屬性查找(既obj.str),如果依然失敗就會嘗試列表查找(即obj[int])。另外循環for中的question.choice_set.all語句會被解析為question.choice_set.all()的 Python 的函數調用,完成后將返回一個可迭代的Choice對象,該對象僅限于for循環標簽內部使用。
在polls/templates/polls/index.html編寫的投票鏈接里使用了諸如<a href="/polls//" rel="external nofollow" ></a>這樣的硬編碼,但是這樣容易造成視圖與后端業務的耦合,因此 Django 提供了url標簽來解決這個問題。
<a href="{% url 'detail' question.id %}" rel="external nofollow" >{{ question.question_text }}</a>
實際上在mysite/polls/urls.py內的函數調用path('<int:question_id>/', views.detail, name='detail')當中,path()的name屬性就是作用于url標簽中的這個特性的。
為了避免項目當中各種應用的 URL 重名,避免url標簽被使用時產生歧義,需要在polls/urls.py上添加應用的命名空間作為區分。
from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.index, name='index'), path('<int:question_id>/', views.detail, name='detail'), path('<int:question_id>/results/', views.results, name='results'), path('<int:question_id>/vote/', views.vote, name='vote'), ]
然后編輯polls/templates/polls/index.html文件,為每個url標簽添加上面聲明的polls:命名空間。
<li><a href="{% url 'polls:detail' question.id %}" rel="external nofollow" >{{ question.question_text }}</a></li>
看完上述內容,你們掌握使用Django2怎么開發一個Web項目的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。