【Django】Django框架基礎詳述(二)
- 2020 年 2 月 14 日
- 筆記
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>