使用Django创建网页的过程通常分三个步骤:定义URL、编写视图函数和编写模板。
每个URL都被映射到特定的视图-视图函数获取处理网页信息的数据。视图通常需要一个模板,后者生成浏览器能理解的网页。
通过浏览器中输入URL以及单机链接来请求网页,在URL配置文件urls.py中设置处理主页(http://localhost:8000)的视图函数。
"""
from django.contrib import admin
from django.urls import path
from learning_logs import views as learn_view
urlpatterns = [
path('admin/', admin.site.urls),
path('', learn_view.index)
]
在应用learning_log的view.py中编写视图函数:
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def index(request):
html = 'Index ' \
'Welcome to Ulysses
' \
'' \
''
return HttpResponse(html)
运行项目,访问主页得到的结果
接下来试着为Topic和Post创建相关链接
urlpatterns = [
path('admin/', admin.site.urls),
path('', learn_view.index),
path('topic//' , learn_view.topic, name='topic'),
path('post//' , learn_view.post, name='post'),
]
可以在URL地址指定捕获的值的类型,如
,指定将url中的’id’转为int型(默认字符串);name
参数相当于是给网址添加了一个名称,可以通过这个name,可以在view,models, templates获取网址。只要这个名字不变,在setting.py中修改了url后,也能通过这个名字获取修改后的网址。
通过reverse(name,args=(,))
获取URL。
>>> from django.urls import reverse
>>> reverse('topic',args=(1,))
'/topic/1/'
>>> reverse('post',args=(1001,))
'/post/1001/'
>>>
topic和post视图函数:当访问 ‘http://127.0.0.1:8000/topic/1/’ 时,获取topic_id,在数据库中查询获取对于的topic,将id和text存储在要发送给模板的上下文context
中。render
接受上下文并讲其赋值给appname/templates下指定的网页,返回一个HttpResponse
。当id对应的post或topic不存在时, QuerySet生成DoesNotExist
错误。
def topic(request, topic_id):
"""根据id访问topic的信息"""
try:
t = Topic.objects.get(id=topic_id)
text = t.text
context = {'id':topic_id, 'text':text}
return render(request, 'topic.html', context)
except Topic.DoesNotExist:
return HttpResponseNotFound(f'Topic:{topic_id} not exist
')
def post(request, post_id):
"""根据id访问post信息"""
try:
t = Post.objects.get(id=post_id)
text = t.text
context = {'id': post_id, 'text': text}
except Post.DoesNotExist:
raise Http404(f'Post:{post_id} not exist')
return render(request, 'post.html', context)
使用HttpResponseNotFound
来定义错误界面,Web最常见的错误类型就是404错误。手动抛出Http404
错误,Django会捕获这个错误并返回一个标准的404错误界面和404错误码。
Django的404错误界面
POST界面
模板是包含响应文本的文件,其中包含占位变量表示的动态部分,其具体值只在请求的上下文才知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染
。
{% %}
{{ }}
{# #}
{# Django #}
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
a>
h2>
<p>{{ story.tease|truncatewords:"100" }}p>
{% endfor %}
{% endblock %}
在模板中的{{ i }}
结构表示变量,这是一种特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据结构中获取。Django支持python中所有的Python数据类型比如列表、字段、对象等
<p>this is a dicectory:{{ mydict['key'] }} p>
<p>this is a list:{{ mylist[3] }} p>
<p>this is a object:{{ myobject.something() }} p>
{% for k, v in defaultdict.items %}
Do something with k and v here...
{% endfor %}
变量的值可以使用过滤器修改。过滤器在添加变量名后,二者以竖线分隔。如:
<p>Hello, {{ user|capitalize }}!p>
有些过滤器带有参数: {{ bio|truncatewords:30 }}
:会显示bio的前30个单词。当参数中有空格
时必须带引号,如 {{ list|join:", " }}
。
过滤器名 | 说明 | example |
---|---|---|
add | 加法运算,给变量加一个值,当两个变量都为列表时,相当于extend | {{ value|add:"2" }} {{ first|add:second }} |
addslashes | 给引号前加斜杠: "I\'m using Django" |
{{ value|addslashes }} |
capfirst | 首字母大写:django-> Django | {{ value|capfirst }} |
center | 指定变量居中:" Django " |
"{{ value|center:"15" }}" |
cut | 除去变量中的指定值 “String with spaces” -> “Stringwithspaces” | {{ value|cut:" " }} |
date | 指定日期时间的输出格式 | {{ value|date:"D d M Y" }} |
default | 变量的值为False或为空指定一个默认值 | {{ value|default:"nothing" }} |
default_if_none | 变量值为且仅为None时,指定默认值 | {{ value|default_if_none:"nothing" }} |
dictsort | 根据给定的键对字典进行排序,也可对序列的列表进行排序 | {{ value|dictsort:"name" }} {{ value|dictsort:0 }} |
dictsortreversed | 排序,与dictsort相反 | |
divisibleby | 是否内被整除,返回True,False | {{ value|divisibleby:"3" }} |
escape | 转义HTML字符串< 变为< |
{% autoescape off %} {{ title|escape }} {% endautoescape %} |
escapejs | 转义javascript字符 | {{ value|escapejs }} |
filesizeformat | 将值的大小,格式化为易读的形式’13 KB’, ‘4.1 MB’, ‘102 bytes’, etc | {{ value|filesizeformat }} |
first | 返回列表的首个元素 | {{ value|first }} |
floatformat | 省略小数位,默认舍入到一个小数位 | {{ value|floatformat : 3}} |
force_escape | 转义多个HTML字符串 | {% autoescape off %} {{body|linebreaks|force_escape }} {% endautoescape %} |
get_digit | 获取指定位置数值,从右数起 | {{ value|get_digit:"2" }} |
iriencode | 转义iri字符 | {{ value|iriencode }} |
join | 给序列增加一个字符串,像python的str.join(list) | {{ value|join:" // " }} |
json_script | 将Python数据以JSON形式输出 | {{ value|json_script:"hello-data" }} |
last | 输出序列的最后一个元素 | {{ value|last }} |
length | 变量的长度 | {{ value|length }} |
length_is | 变量长度是否为指定值 | {{ value|length_is:"4" }} |
linebreaks | 使用HTML的换行符单换行: ,换行空行
|
{{ value|linebreaks }} |
linebreaksbr | 使用 换行 |
{{ value|linebreaksbr }} |
linenumber | 显示行号 | {{ value|linenumbers }} |
ljust | 左对齐 | "{{ value|ljust:"10" }}" |
lower | 全部变为小写 | {{ value|lower }} |
make_list | 将变量拆分成列表形式 | {{ value|make_list }} |
phone2numeric | 将电话号码(可能包含字母)转换为其等效数字 | {{ value|phone2numeric }} |
pluralize | 返回复数后缀,默认’s’ | {{ num_messages|pluralize }} |
pprint | 包装了pprint.pprint()的装饰器 | |
random | 返回变量列表的随机元素 | {{ value|random }} |
rjust | 右对齐 | "{{ value|rjust:"10" }}" |
safe | 将字符串标记为在输出之前不需要进一步的HTML转义。当autoescaping关闭时,此过滤器无效 | {{ var|safe|escape }} |
safeseq | 将安全过滤器应用于序列的每个元素。 与在序列上运行的其他过滤器结合使用,例如join |
{{ some_list|safeseq|join:", " }} |
slice | 返回切片 | {{ some_list|slice:":2" }} |
slugify | 转换为ASCII码,将空格转换为连字符。 删除不是字母数字,下划线或连字符的字符。 转换为小写。 还剥去前导和尾随空格。 | {{ value|slugify }} |
stringformat | 根据参数格式化变量,10->1.000000E+01 |
{{ value|stringformat:"E" }} |
striptags | 去除[X]HTML标记 | {{ value|striptags }} |
time | 格式化时间格式 | {{ value|time:"H:i" }} |
timesince | 自给定时间后过去了的间隔(e.g., “4 days, 6 hours”) | {{ blog_date|timesince:comment_date }} |
timeuntil | 距给定时间还有… | {{ conference_date|timeuntil:from_date }} |
title | 将字符转为标题形式 | {{ value|title }} |
truncatechars | 如果字符串长于指定的字符数,则截断该字符串 | {{ value|truncatechars:9 }} |
truncatechars_html | 截短HTML标签内字符 | {{ value |
truncatewords | 根据指定数值截断单词 | {{ value|truncatewords:2 }} |
truncatewords_html | 截短HTML标签内的单词 | {{ value|truncatewords_html:2 }} |
unordered_list | 递归地获取自嵌套列表并返回HTML无序列表 - 没有打开和关闭 标记。 |
{{ var|unordered_list }} |
upper | 大写 | {{ value|upper }} |
urlencode | 转义变量中的url的 | {{ value|urlencode }} |
urlize | 将url和email地址转换为可点击的形式 | {{ value|urlize }} |
urlizetrunc | 将url和email地址转换为可点击的形式,限制长度 | {{ value|urlizetrunc:15 }} |
wordcount | 单词数统计 | {{ value|wordcount }} |
wordwrap | 根据给的行长度包装 | {{ value|wordwrap:5 }} |
yesno | 映射True, False, None | {{ value|yesno:"yeah,no,maybe" }} |
{'name':'Hello'}
结果为Hello
{'name':'Hello'}
结果为Hello{'name':'Hello'}
结果为Hello默认情况下出于安全考虑会转义所有变量。当一个变量为Hello
没有添加safe过滤器时,显示的结果为
浏览器能显示元素,但不会解释它。
当添加safe过滤器时,结果为
当需要显示变量中存储的HTML代码时,可使用safe过滤器。
条件判断语句与Python类似,但其不需要使用冒号结尾,而结束控制语句,需要使用endif
关键字:
{% if daxin.safe %}
daxin is safe.
{% elif daxin.dead %}
daxin is dead
{% else %}
daxin is okay
{% endif %}
for循环实现一组元素的渲染:
<ul>
{% for user in users %}
<li>{{ user.username|title }}li>
{% endfor %}
ul>
模板继承类似于python代码的类继承。首先创建名为base.html的基模板:
<html lang="en">
<head>
<title>{% block title %}My amazing site{% endblock %}title>
head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Homea>li>
<li><a href="/blog/">Bloga>li>
ul>
{% endblock %}
div>
<div id="content">
{% block content %}{% endblock %}
div>
body>
html>
基模板中定义的区块可在衍生模板中覆盖。使用block
和endblock
指令在基模板中定义内容区块。在上述基模板中定义了head、title、content和footer区块。
新建一个topics.html的文件,继承基模板,用来显示全部的topics。
{% extends "base.html" %}
{% block title %}Topics{% endblock %}
{% block head %}
{{ block.super }}
{% endblock %}
{% block content %}
{% for topic in topics %}
<h2>{{ topic.id }}h2>
<p>{{ topic.text }}p>
{% endfor %}
{% endblock %}
extends
指令声名这个模板衍生自base.html。在extends指令后,基模板的4个区块被重新定义,模板引擎将其插入合适的位置。如果基模板和衍生模板的同名区块有内容,衍生模板的内容会被显示。在衍生模板区块中调用block.super
,引用基模板的同名内容。topics.html里的head区块引用了基模板的css文件。
在应用目录下创建static文件夹,存放css、图片等静态文件:
指定css文件路径
{# jinja2 #}
{% block head %}
{# django #}
{% load static %}
<img src="{% static 'img/nan.jpg' %}" alt="南风不竞"/>
视图函数:
def topics(request):
"""全部的topics"""
topics = Topic.objects.order_by('date_added')
context = {'topics':topics}
return render(request, 'topics.html', context)
def posts(request):
"""全部的posts"""
posts = Post.objects.order_by('date_added')
context = {'posts':posts}
return render(request, 'posts.html', context)
根据添加时间排序,显示全部的内容。
映射url:
urlpatterns = [
path('admin/', admin.site.urls),
path('', learn_view.index),
path('topic//' , learn_view.topic, name='topic'),
path('topics/', learn_view.topics, name='topics'),
path('post//' , learn_view.post, name='post'),
path('posts/', learn_view.posts, name='posts')
]
显示的网页: