1. 程式人生 > >django2.0基礎

django2.0基礎

行數據 last tap -a tro args 文件 led 表單提交

一.安裝與項目的創建

1.安裝

  pip install django

2.查看版本

  python -m django --version

3.創建項目

  django-admin startproject mysite

    manage.py 實用的與django項目進行交互的命令行工具
    mysite 項目中的實際python包
    mysite/__init__.py 空文件,表示這是一個python包
    mysite/settings.py 此項目的配置文件
    mysite/urls.py url聲明文件
    mysite/wsgi.py wsgi服務器的配置文件

4.啟動開發模式下的服務器

  python manage.py runserver 0.0.0.0:8000

    瀏覽器訪問:http://127.0.0.1:8000/

5.創建應用

  在manage.py的同級目錄下執行:

    python manage.py startapp molin

6.第一個視圖文件

polls/views.py

#_*_coding:utf8_*_
from django.shortcuts import HttpResponse
def index(request):
    return HttpResponse("你好,歡迎來到投票系統的主頁")

7.配置URL

  新增polls/urls.py文件

#_*_coding:utf8_*_
from django.urls import path
from . import views
urlpatterns = [
    path(‘‘, views.index, name=index),
]

8.將polls/urls.py引入到mysite/urls.py文件中, 因為所有的url配置入口都是源於mysite/urls.py

  mysite/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path(
polls/, include(polls.urls)), path(admin/, admin.site.urls), ]
當瀏覽器訪問 http://127.0.0.1:8000/polls/ 時,匹配到url規則path(‘polls/‘, include(‘polls.urls‘)), 然後讀到polls/urls.py的配置:path(‘‘, views.index, name=‘index‘), 從而去執行polls/views.py的index方法

二.模型與數據庫的交互

1.數據庫的設置

  打開mysite/settings.py,可看到默認情況下,django使用的是sqlite3數據庫
DATABASES = {
    default: {
        ENGINE: django.db.backends.sqlite3,
        NAME: os.path.join(BASE_DIR, db.sqlite3),
    }
}

有些應用要求我們必須至少要有一個數據庫,如,django的後臺,因此,讓我們先來執行以下命令: $ python manage.py migrate

  將django激活的應用所需的數據表創建好

2.創建模型

  polls/models.py

#_*_coding:utf8_*_

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)

類中的每個屬性映射為一個字段,並標識了這些字段的類型

3.激活模型

  mysite/settings.py

INSTALLED_APPS = [
    polls.apps.PollsConfig,
    # ...
]

4.生成遷移

  $ python manage.py makemigrations polls

  自動生成了polls/migrations/0001_initial.py文件,現在還沒有真正創建數據表,需要再執行數據遷移才能生成數據表

  執行遷移:$ python manage.py migrate

5.讓django的命令行交互更友好

  polls/models.py

from django.db import models

class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

__str__()函數將會返回我們定義好的數據格式。此外,我們還可以在models中添加自定義方法:

import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

6.進入交互模式對數據庫進行操作

  $ python manage.py shell

In [1]: from polls.models import Question, Choice

In [2]: Question.objects.all() # 獲取所有問題
Out[2]: <QuerySet [<Question: 問題2>]>

In [3]: Question.objects.filter(id=1) # 獲取id為1的數據
Out[3]: <QuerySet [<Question: 問題2>]>

In [8]: Question.objects.filter(question_text__startswith=‘問題‘) # 獲取內容包含‘問題‘的數據
Out[8]: <QuerySet [<Question: 問題2>]>

In [9]: from django.utils import timezone

In [10]: current_year = timezone.now().year

In [11]: Question.objects.get(pub_date__year=current_year)
Out[11]: <Question: 問題2>

In [12]: Question.objects.get(id=2) # 當獲取的數據不存在時,會報以下錯誤
---------------------------------------------------------------------------
DoesNotExist                              Traceback (most recent call last)
<ipython-input-12-75091ca84516> in <module>()
----> 1 Question.objects.get(id=2)


In [13]: Question.objects.get(pk=1)
Out[13]: <Question: 問題2>

In [14]: q = Question.objects.get(pk=1)

In [15]: q.was_published_recently() # 調用自定義的方法
Out[15]: True

In [16]: q = Question.objects.get(pk=1)

In [17]: q.choice_set.all()
Out[17]: <QuerySet []>
In [19]: q.choice_set.create(choice_text=‘選項1‘, votes=0)
Out[19]: <Choice: 選項1>

In [20]: q.choice_set.create(choice_text=‘選項2‘, votes=0)
Out[20]: <Choice: 選項2>

In [21]: c = q.choice_set.create(choice_text=‘選項3‘, votes=0)

In [22]: c.question
Out[22]: <Question: 問題2>

In [23]: q.choice_set.all()
Out[23]: <QuerySet [<Choice: 選項1>, <Choice: 選項2>, <Choice: 選項3>]>

In [24]: q.choice_set.count()
Out[24]: 3
In [25]: Choice.objects.filter(question__pub_date__year=current_year)
Out[25]: <QuerySet [<Choice: 選項1>, <Choice: 選項2>, <Choice: 選項3>]>

In [26]: c = q.choice_set.filter(choice_text__startswith=‘選項3‘)

In [27]: c.delete()
Out[27]: <bound method QuerySet.delete of <QuerySet [<Choice: 選項3>]>>

In [29]: Choice.objects.filter(question__pub_date__year=current_year)
Out[29]: <QuerySet [<Choice: 選項1>, <Choice: 選項2>]>

7.創建後臺管理員   

django自帶了一個管理後臺,我們只需創建一個管理員用戶即可使用
創建一個後臺管理員用戶: $ python manage.py createsuperuser

8.引入模型

  polls/admin.py

#_*_coding:utf8_*_
from django.contrib import admin
from .models import Question
admin.site.register(Question)

登陸後臺可以對模型進行操作

三.視圖views和模板template的操作

1.django的視圖用於處理url請求,並將響應的數據傳遞到模板,最終瀏覽器將模板數據進行渲染顯示,用戶就得到了想要的結果

  增加視圖:polls/views.py

#_*_coding:utf8_*_
from django.shortcuts 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)

  配置url:polls/urls.py

#_*_coding:utf8_*_
from django.urls import path
from . import views
urlpatterns = [
    # /polls/
    path(‘‘, views.index, name=index),
    # /polls/1/
    path(<int:question_id>/, views.detail, name=detail),
    # /polls/1/results/
    path(<int:question_id>/results/, views.results, name=results),
    # /polls/1/vote/
    path(<int:question_id>/vote/, views.vote, name=vote),
]

2.通過視圖直接返回的數據,顯示格式很單一,要想顯示豐富的數據形式,就需要引用模板,用獨立的模板文件來呈現內容。

  新增模板:polls/templates/polls/index.html

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
    <li><a href="/polls/{{question.id}}/">{{question.question_text}}</a></li>
    {% endfor %}
    </ul>    
{% else %}
    <p>問題為空</p>
{% endif %}

  修改視圖: polls/views.py 傳遞變量給模板

#_*_coding:utf8_*_
from django.shortcuts 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()即可,盡可能精簡代碼

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)

詳情頁的展示: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: question})

404頁面拋出的便捷寫法:get_object_or_404()

polls/views.py

from django.shortcuts import render, get_object_or_404
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})

詳情頁輸出關聯數據表:

<h1>{{ question.question_text }}</h1>
<ul>
    {% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
    {% endfor %}
</ul>

3.優化

  去掉url的硬編碼格式

<li><a href="{% url ‘detail‘ question.id %}">{{question.question_text}}</a></li>

  修改url配置 

  將polls/urls.py的詳情頁url由:path(‘<int:question_id>/‘, views.detail, name=‘detail‘)改為:     path(‘specifics/<int:question_id>/‘, views.detail, name=‘detail‘)

    此時,index.html的url會自動由 http://127.0.0.1:8000/polls/1/ 轉為 http://127.0.0.1:8000/polls/specifics/1/

4.一個項目中多個應用的區分需要使用命名空間

#_*_coding:utf8_*_
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),
]

將index.html的url生成代碼加上命名空間:

<li><a href="{% url ‘polls:detail‘ question.id %}">{{question.question_text}}</a></li>

四.在前臺進行投票操作

1.構建一個簡單的表單提交頁

  polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{%url ‘polls:vote‘ question.id %}" method="post">
    {% csrf_token %}
    {% for choice in question.choice_set.all %}
    <input id="choice{{ forloop.counter }}" type="radio" name="choice" value="{{ choice.id }}">
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
    {% endfor %}
    <br />
    <input type="submit" name="" id="" value="投票" />
</form>

代碼解析:

  form表單提交的url為{%url ‘polls:vote‘ question.id %}, 即表示訪問polls/views.py的vote方法,並攜帶問題id作為參數。

  將問題的相關選項遍歷,以單選框顯示

  form表單用post方式提交數據

配置url: polls/urls.py

path(<int:question_id>/vote/, views.vote, name=vote),

2.視圖層處理提交結果

  polls/views.py

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from .models import Question, Choice
# ...
def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST[choice])
    except (KeyError, Choice.DoesNotExist):
        return render(request, polls/detail.html, {
            question: question,
            error_message: "必須選擇一個選項",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return HttpResponseRedirect(reverse(polls:results, args=(question.id,)))

代碼解析:

request.POST[‘choice‘]接收表單頁面提交的數據

將投票次數加1,並更新數據庫

3.顯示投票結果

  polls/views.py

from django.shortcuts import render, get_object_or_404
# ...
def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, polls/results.html, {question: question})

  results.html

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{choice.votes}}</li>
{% endfor %}
</ul>

<a href="{% url ‘polls:detail‘ question.id %}">再投一次?</a>

4.優化url和view寫法

  將主鍵id代替question_id
  polls/urls.py

#_*_coding:utf8_*_
from django.urls import path
from . import views
app_name = polls
urlpatterns = [
    path(‘‘, views.IndexView.as_view(), name=index),
    path(<int:pk>/, views.DetailView.as_view(), name=detail),
    path(<int:pk>/results/, views.ResultsView.as_view(), name=results),
    path(<int:question_id>/vote/, views.vote, name=vote),
]

使用<pk>代替<question_id>會更加靈活,<pd>代表主鍵

相應的視圖也需要修改成另一種寫法,vote方法保持原樣,用於比較兩種寫法的不同

polls/views.py

#_*_coding:utf8_*_
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic 
from .models import Question, Choice

class IndexView(generic.ListView):
    template_name = polls/index.html
    context_object_name = latest_question_list

    def get_queryset(self):
        return Question.objects.order_by(-pub_date)[:5]

class DetailView(generic.DetailView):
    model = Question
    template_name = polls/detail.html

class ResultsView(generic.DetailView):
    model = Question
    template_name = polls/results.html

def vote(request, question_id):
    # ...

  


django2.0基礎