【Django】Django框架基礎詳述(二)

1、模板Template

(1)模板Template使用 django內置了自己的模板引擎,和jinja很像,使用簡單。

>>> from django.template import Template, Context  >>> t = Template('My name is {{ name }}')  >>> c = Context({'name': 'guang'})  >>> t.render(c)

(2)點號的使用

>>> t = Template('Person is {{ person.name }}')  >>> person = {'name': 'guang'}								# 點號用於字典  >>> t.render(Context({'person': person}))  	'Person is guang'  >>> class Person:  ...     def __init__(self, name):  ...         self.name = name  								# 點號用於屬性  >>> person = Person('hongwei'}  >>> t.render(Context({'person': person}))  	'Person is hongwei'  >>> class Person:  		pass  >>> p = Person()  >>> p.name = 'guanghongwei'									# 點號用於屬性  >>> t.render(Context({ 'person': p}))  	'Person is guanghongwei'  >>> p.name = lambda: 'guanggg'								# 點號用於方法  >>> p.name  	<function __main__.<lambda>>  >>> p.name()  	'guanggg'  >>> t.render(Context({ 'person': p }))  	'Person is guanggg'  >>> class Person:  ...     def name(self):										# 點號用於方法  ...         return 'guanghongwei'  >>> person = Person()  >>> t.render(Context({ 'person': person }))  	'Person is guanghongwei'  >>> person = ['guang', 'hongwei']							# 點號用於列表  >>> t = Template('Person is {{ person.0 }}')  >>> t.render(Context({ 'person': person}))  	'Person is guang'  >>> person = ('guang', 'hongwei')							# 點號用於元組  >>> t = Template('Person is {{ person.1 }}')  >>> t.render(Context({ 'person': person}))  	'Person is hongwei'

點號表示的變量查找是有順序的:字典 –> 屬性 –> 方法 –> 列表/元組。 點號表示的函數和方法是不能帶任何參數的。 (3)For循環

>>> t = Template('''{% for person in person_list %}  					<li> {{ person.name }} </li>  					{% endfor %}''')  >>> person_list = [{'name': 'guang'}, {'name': 'mage'}]  >>> c = Context(person_list)  >>> t.render(c)  	'n<li> guang </li>nn<li> mage </li>n'  >>> person = [{'name': 'guang'}, {'name': 'mage'}]  >>> c = Context({'person_list': person})  >>> t.render(c)  	'n<li> guang </li>nn<li> mage </li>n'

(4)if判斷

{% if max > 10 %}  <li>最大值 {{ max }} </li>  {% else %}  <li> 最大值 10 </li>  {% endif %}

(5)內置過濾器

{{ now | date:」F j,Y」 }}  {{ name | length }}    >>> t = Template('Today is {{ now | date:"F j, Y" }}  >>> now = timezone.now()  >>>t.render(Context({ 'now': now }))     'Today is January 21, 2020'  # 相當於調用如下函數:  def date(datetime, format)    >>> t = Template('My name length is {{ name | length }}')  >>> c = Context({'name': 'guang'})  >>> t.render(c)  	'My name length is 5'  # 相當於調用如下函數:  def length(text):  	return len(text)

(6)view中使用模板 django默認會去app_name/templates下尋找模板,這是settings中的默認設置,默認會去app_name/static中尋找靜態文件(css,js,jpg)。 version 1

# polls/views.py  from django.template import Template, Context    def index(request):      latest_question_list = Question.objects.order_by('-pub_date')[:5]      template = Template("""      <img src="/static/django.png">      {% if latest_question_list %}      <ul>        {% for question in latest_question_list %}        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }} </a></li>        {% endfor %}      </ul>      {% endif %}      """)      context = Context({'latest_question_list': latest_question_list})      return HttpResponse(template.render(context))

version 2

# polls/templates/polls/index.html    <img src="/static/django.png">  {% if latest_question_list %}  <ul>    {% for question in latest_question_list %}    <li><a href="/polls/{{ question.id }}/">{{ question.question_text }} </a></li>    {% endfor %}  </ul>  {% endif %}    # polls/views.py  from django.template import loader    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))

version 3

# polls/templates/index.html    <img src="/static/django.png">  {% if latest_question_list %}  <ul>    {% for question in latest_question_list %}    <li><a href="/polls/{{ question.id }}/">{{ question.question_text }} </a></li>    {% endfor %}  </ul>  {% endif %}    # polls/views.py  from django.shortcuts import render    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)

說明:version 3中,

  • render:新版本Django函數,第一個參數必須為request
  • render_to_response:老版本Django函數,不需要request參數

(7)設置公用 templates 和 static

# mysite/settings.py  ...  BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  TEMPLATES = [      {          'BACKEND': 'django.template.backends.django.DjangoTemplates',          'DIRS': [os.path.join(BASE_DIR, 'templates')],          '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',              ],          },      },  ]  ...  STATIC_URL = '/static/'  STATICFILES_DIRS = [      os.path.join(BASE_DIR, 'static'),  ]

(8)去掉url和static硬編碼

# polls/templates/polls/index.html  {% load static %}    {# <img src="/static/django.png"> #}  <img src="{% static 'django.png' %}">  {% if latest_question_list %}  <ul>    {% for question in latest_question_list %}    {# <li><a href="/polls/{{ question.id }}/">{{ question.question_text }} </a></li> #}    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }} </a></li>    {% endfor %}  </ul>  {% endif %}

(9)url 反解析

  • 正解析: url -> view
  • 反解析: view name -> url
>>> from django.shortcuts import reverse  >>> reverse('detail', kwargs={'question_id': '1'})  '/polls/1/  >>> reverse('detail', args=(123,))  '/polls/123/

說明:

  • reverse
  • reverse_lazy

(10)url命名空間

  • app namespace
  • instance namespace

1)app namespace app級別的,名稱可以重複。 定義方法1:

# polls/urls.py  ...  app_name = 'polls'

定義方法2:

# mysite/urls.py    ...  url(r'^polls/', include('polls.urls', app_name='polls')),

2)instance namespace instance級別,名稱不可以重複。 定義:

# mysite/urls.py  ...  url(r'^polls/', include('polls.urls', namespace='polls')),

3)測試 修改templates代碼:

# polls/templates/polls/index.html  {% load static %}    {# <img src="/static/django.png"> #}  <img src="{% static 'django.png' %}">  {% if latest_question_list %}  <ul>    {% for question in latest_question_list %}    {# <li><a href="/polls/{{ question.id }}/">{{ question.question_text }} </a></li> #}    <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }} </a></li>    {% endfor %}  </ul>  {% endif %}
>>> from django.urls import reverse  >>> reverse('polls:detail', kwargs={'question_id': 1})

什麼時候用 app namespace?什麼時候用 instance namespace? 一般情況下使用 app namespace,如果你的app有多個include,則使用instance namespace。

[      urls('^polls/', include('polls.view_urls')),      urls('^api/polls/', include('polls.api_urls')),  ]

2、form處理

# 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 type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />      <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />  {% endfor %}  <input type="submit" value="Vote" />  </form>    # polls/views.py    from django.shortcuts import get_object_or_404, render  from django.http import HttpResponseRedirect, HttpResponse  from django.core.urlresolvers import reverse  from .models import Choice, 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)    def detail(request, question_id):  	question = get_object_or_404(Question, id=question_id)  	return render(request, 'polls/detail.html', {'question': question})    def results(request, question_id):  	response = "You are looking at results of question {}".format(question_id)  	return HttpResponse(response)    def vote(request, question_id):      question = get_object_or_404(Question, pk=question_id)      if request.method == 'POST':          choice_id = request.POST.get('choice', 0)          try:              selected_choice = question.choice_set.get(pk=choice_id)          except Choice.DoesNotExist:              # Redisplay the question voting form.              return render(request, 'polls/detail.html', {                  'question': question,                  'error_message': "You didn't select a choice.",              })          else:              selected_choice.votes += 1              selected_choice.save()              # Always return an HttpResponseRedirect after successfully dealing              # with POST data. This prevents data from being posted twice if a              # user hits the Back button.              return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))      else:      	return HttpResponse('Your post question id: %s' % question.id)

說明:

  • request.POST:返回QueryDict。
  • csrf_token:form里使用,防止跨站攻擊,默認啟用該中間件。
  • getlist:多選框或下拉列表獲得一個list,get只能得到第一個值。
  • request.FILES:上傳文件時獲取form中的內容。
  • request.GET:返回QueryDict,獲取的是提交的url中的參數和get請求提交的內容。
  • Choice.DoesNotExist:GET不能獲取內容的話,報該異常。
  • HttpResponseRedirect:重定向,表單post後需要重定向到另一個頁面,防止用戶重複提交。
  • get_object_or_404:得到對象返回對象,得不到返回404異常。
  • get_list_or_404:objects.filter獲取不到list,返回404異常。
  • redirect
>>> from django.shortcuts import redirect  >>> redirect('http://www.qq.com')  <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="http://www.qq.com">
  • request
    • META HTTP_REFERER, HTTP_USER_AGENT, REMOTE_ADDR
    • schema method COOKIES FILES
    • path, get_host, get_full_path, is_secure

3、results頁面

#polls/views.py  from django.shortcuts import get_object_or_404, render    def results(request, question_id):      question = get_object_or_404(Question, pk=question_id)      return render(request, 'polls/results.html', {'question': question})      #polls/templates/polls/results.html    <h1>{{ question.question_text }}</h1>    <ul>  {% for choice in question.choice_set.all %}      <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>  {% endfor %}  </ul>    <a href="{% url 'polls:detail' question.id %}">Vote again?</a>