Django(二):进阶------扩充urls、views、templates
查看Django框架的安装位置:
python -c " import sys sys.path = sys.path[1:] import django print(django.__path__)" ['/root/.pyenv/versions/magedu/lib/python3.5/site-packages/django']
查看Django框架的版本:
# django-admin --version
查看Django框架的组件、及其帮助
# django-admin help //或者--help, -h, 查看到组件
# django-admin help 组件名称 //查看某一组件的帮助
一、URLconf
1.Django如何处理一个请求:
1).项目启动后根据settings ROOT_UNRLCONF决定URLconf变量;
2).它是django.conf.urls.url()实现的一个python列表
3).django依次匹配urlpatterns列表中的每个URL模式,在与请求的URL匹配的第一个模式停下来;
4).一旦其中的一个正则表达式匹配上,django将导入并调用给出的视图,它是一个简单的python函数(或者一个基于类的视图)。视图将获得如下参数:
一个HttpRequest实现;
如果匹配的正则表达式返回了没有命名的组,那么正则表达式匹配的内容将作为位置参数提供给视图;
关键字参数由正则表达式匹配的命名组成,但是可以被django.conf.urls.url()的可选参数kwargs覆盖;
5).如果没有匹配到正则表达式,或者如果过程中抛出一个异常,django将调用一个适当的错误处理视图
示例:
urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'articles/([0-9]{4})/$', views.year_archive), url(r'^arcticles/([0-9]{4})/([0-9]{2})/$', views.month_archives), url(r'^arcticles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ]
说明:
1).若要从URL中捕获一个值,只需要在它周围放置一对圆括号()即可。
2).不需要添加一个前导的反斜杠"/",因为每个URL结尾都有。例如,应该是^articles,而不是^/articles。
3).每个正则表达式前面的'r',是可选的,但是建议加上。加上r后,是告诉python,这个字符串是原始的,其中的任何字符都不需要转义。
4). /articles/2005/03/请求,将匹配列表中的第三个模式。django将调用函数views.month_archives(request, '2005', '03')。
/articles/2005/03/?blog=hi,和上面一样,调用第三个模式。
/articles/2005/3请求,不匹配任何模式,因为列表中的第三个模式要求月份为两个数字。
/articles/2003/请求,将匹配列表中的第一个模式而不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。
/articles/2003请求,不匹配任何模式,因为以上列表中的每个模式都要求URL以斜杠结尾。
/articles/2003/03/03/请求,将匹配第四个模式。调用函数views.article_detail(request, year='2003', month='03', day='03')。
默认捕捉的都是字符串。
错误处理:当django找不到一个匹配请求的URL的正则表达式时,或者当抛出一个异常时,django将调用一个错误处理函数。默认的错误处理函数有:
handler404、handler500、handler403、handler400
2.URL的多种写法
分组: urlpatterns += []
或者定义一个变量,如extend_url = [ url.........];再include进去。
include:可以是某个app的urls.py,如include('polls.urls');也可以是变量,如include(myurls); 也可以在include里直接写url模式。
3.URL可以上下层传递参数、也可以传递额外选项
4.URL反向解析
在模板中,使用URL模板标签;
在python代码中,使用django.core.urlresolvers.reverse()函数;
在更高层的与处理django模型补全相关的代码中,使用get_absolute()方法。
在定义URL时,可以传递变量给视图函数,
如url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}。{‘foo':'bar'}会将'bar'传递给视图函数year_archive(request, year, foo)中的参数foo。
如url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'year': '2005'})。{'year': '2005'}会将'2015'传递给视图函数year_archive(request, year, foo)中的参数year;同时,{'year': '2005'}在这里强制代替了命名捕获(?P<year>[0-9]{4})。
5.手动定义404
return HttpResponse('Not Found.....', status=404) or return HttpResponse('Not Found.....')
6.自定义错误视图
# urls.py handler404 = 'mysite.views.my_custom_page_not_found_view' handler500 = '.......' handler403 = ...... handler400 = ......
# polls/views.py
def polls_404_handler(request): return HttpResponseNotFound('Not Found')
# 项目/urls.py
handler404 = 'polls.views.polls_404_handler' #需要在项目的urls.py定义;在app/urls.py中定义貌似不ok
二、views
render()函数:
from django.shortcuts import render
render(request, template_name, context=None, content_type=None, status=None, using=None)[source]
template_name模板名称
context,渲染模板时用到的context字典,格式为{"模板中用到的名称": python中用到的变量名”或字符等"}
content_type默认是HTML,即返回的是HTML页面,DEFAULT_CONTENT_TYPE setting中的设置。如果需要返回json字符串等等,在此定义。
status默认200 using,当有多个模板引擎时才会用到
redirect()函数:
from django.shortcuts import redirect
第一个参数to,即可以是直接的URL,也可以是相对的URL,还可以是模型url,还可以是一个视图处理函数。
object = Mymodel.objects.get(...) redirect(object) #to为model redirect('some-view-name') #to为视图函数
redirect('some-view-name', foo='bar') #to为视图函数且带(视图函数的)参数
redirect('some/url/') #to为相对url
redirect('https://example.com/', permanent=True) #to为直接url
第二个参数permanent,临时重定向还是永久重定向,默认为False,临时重定向302。True,则为301永久重定向。
redirect(to, permanent=False, *args, **kwargs){source}
get_object_or_404()函数:
def myview():
my_object = get_object_or_404(MyModel, pk=1) #上下的两种方法是相等的,使用get_object_or_404,节省了代码
def myview(): try: my_object = MyModel.objects.get(pk=1) except MyModel.DoesNotExist: raise Http404("No MyModel matches the given query")
reverse()和reverse_lazy()函数:
from django.urls import reverse, reverse_lazy
from myapp import views
reverse('detail', args=(1, )) # 返回'/myapp/1/'
reverse('detail', kwargs={'question_id': 1}) #返回'/myapp/1/'
reverse_lazy('detail', args=(1, )) # 返回生成器
reverse_lazy('detail', kwargs={'question_id': 1}) #返回生成器,<django.utils.functional.lazy.<locals>.__proxy__ at 0x7f19e88d7828>
reverse,直接返回值;reverse_lazy,返回一个生成器,当调用时才返回值。当项目还没有加载的时侯,需要用reverse_lazy。
场景:在models定义ORM时,假如需要用到URL,这种场景应该使用reverse_lazy。因为django的启动顺序是,先启动model,后启动url;那么在model启动时,使用reverse无法反解出url,将抛出异常;而使用reverse_lazy,则不会抛出异常,因为reverse_laze并不会马上返回值,而是等到调用它时,才会返回值。
get_list_or_404
from django.shortcuts import get_object_or_404, get_list_or_404
请求方式相关的装饰器: django.views.decorators.{http|gzip|cache|...}.{...}
from django.views.decorators.http import require_http_methods, require_GET, require_POST, require_safe
1).请求方法的装饰器:require_http_methods(["请求的方式“,”请求的方式"])
如以下示例,如果使用了require_http_methods装饰器,此视图将只允许指定的请求方式访问,其它请求方式的无法访问。这里是只允许POST请求方式可以访问,其它请求方式无法访问。
# polls/views.py from django.views.decorators.http import require_http_methods
@require_http_methods(["POST"]) def vote(request, question_id): pass
2).具体请求方法的装饰器:require_GET,require_POST,require_safe
require_safe,安全的方法,即只允许读的操作,不允许写的操作。
# polls/views.py
from django.views.decorators.http import require_safe
@require_safe
def vote(request, question_id):
pass
压缩有关的装饰器: gzip_page
# polls/views.py
from django.views.decorators.gzip import gzip_page
@gzip_page def detail(request, question_id): pass
浏览器缓存有关的装饰器: cache_control要不要缓存,缓存什么,缓存多长时间、never_cache浏览器不缓存
from django.views.decorators.cache import never_cache @never_cache def index(request, question_id): pass
5).自定义装饰器,如定义只有管理员才有访问权限。
对错误的调试,打开网页,查看源码,进行network,刷新:
可以看到状态码,大小,响应时长;
请求的HEADER:
响应的HEADER:
查看某个模块在什么地方或者其它开发相关的帮助: http://devdocs.io/
HttpRequest、HttpRquest:要进一步了解,参考官方文档 https://docs.djangoproject.com/en/1.10/ref/request-response/
response:

工作流程:1,用户浏览器请求 ->2,modwsgi服务器 ->3,Request Middlewares ->4,读URL配置文件 ->5,Views Middlewares -> 6,调用视图函数 ->7,如果需要读DB,调用Model -> 调用数据库管理器,读取并返回数据给视图函数 -> 8,如果需要渲染模板,调用模板;如果需要filter、tags等操作,操作之 ;结合用户传入的context,渲染后返回 给视图函数->Response Middlewares -> modwsgi服务器 ->返回给用户浏览器
发送邮件:
# setting.py EMAIL_HOST = '' EMAIL_PORT = '' EMAIL_HOST_USER = '' EMAIL_HOST_PASSWORD = '' EMAIL_USE_TLS = True EMAIL_USE_SSL = True
发送邮件:
django.core.mail.send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)
自定义发送邮件的函数,对send_mail作进一步处理:
from django.core.mail import send_mail from django.http import BadHeaderError, HttpResponse, HttpResponseRedirect def send_email(request): subject = request.POST.get('subject', '') message = request.POST.get('message', '') from_email = request.POST.get('from_email', '') if subject and message and from_email: try: send_mail(subject, message, from_email, ['admin@example.com']) except BadHeaderError: return HttpResponse('Invalid header found.') return HttpResponseRedirect('/contact/thanks/') else: return HttpResponse('Make sure all fields are entered and valid.')
导出CSV,示例:
# polls/views.py
import csv from django.http import HttpResponse def export_cvs(request): response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="somefilename.csv"' writer = csv.writer(response) writer.writerow(['First row', 'Foo', 'Bar', 'Baz']) writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"]) return response
# polls/urls.py urlpatterns = [ url(r'^export/$', views.export_cvs, name='export') ]
上传文件,示例:
# polls/views.py
from django.shortcuts import render from django.http import HttpResponse def upload(request): if request.method == 'POST': upload_file = request.FILES.get('file', None) if upload_file is None: return HttpResponse('Not file get') else: with open('/tmp/%s' % upload_file.name, 'wb') as f: f.write(upload_file.read()) return HttpResponse('already upload.') else: return render(request, 'polls/upload.html')
# polls/templates/polls/upload.html <form method="post" action="" enctype="multipart/form-data"> {% csrf_token %} <label> upload </label> <input type="file" name="file"> <input type="submit" value="upload"> </form>
# polls/urls.py urlpatterns = [ url(r'^upload/$', views.upload, name='upload'), ]
下载文件,示例:
# polls/views.py def dowload(request): f = open('tmp/tet.csv', 'rb') response = HttpResponse(f, content_type='application/csv') response['Contet-Disposition'] = 'attached; filename=test.csv' f.close() return response
# polls/urls.py
urlpatterns = [
url(r'^download/$', views.download, name='download'),
]
三、Template模板
变量: {{ var }}、{{ dict.key }}、{{ var.attr }}、{{ var.index }}
过滤器: {{ list|过滤器:"参数,参数" }}、{{ name|lower }}
Tags标签:{% tag 参数 %}...{% endtag %}、{% for ... %}...{% endfor%}、{# comment #}注释
配置template引擎:
# mysite/settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates',
#'BACKEND': 'django.template.backends.jinja2.Jinja2', #如果要使用jinja2模板,修改这里 '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', ], }, }, ]
获取和渲染模板:
loader.get_template(): django.template.loader.get_template(template_name, using=None)
render():django.shortcuts.render()
Template.render(context=None, request=None):
loader.render_to_string(): django.template.loader.render_to_string(template_name, context=None, request=None, using=None)
Context({ : }):构造类字典
上下文处理器context_processors,定义在settings的TEMPLATES引擎中。它们所包含的变量或标签,可以直接用在模板中:
'django.contrib.auth.context_processors.auth'中,包含的常用变量:user、perms
'django.template.context_processors.debug'中, 包含的标签: debug、sql_query;需要将DEBUG改为True。用于测试环境。
'django.template.context_processors.request'中,包含的变量
'django.contrib.messages.context_processors.messages',包含
'django.template.context_processors.media'中,包含的变量:MEDIA_URL
'django.template.context_processors.static'中,包含的标签:static
'django.template.context_processors.csrft'中,包含的变量:
内置的template tag和filter: 详细内容考官方文档 https://docs.djangoproject.com/en/dev/ref/templates/builtins/
{% url 'some-url-name' arg1 arg2 %}, {% url 'some-url-name' arg1=v1 arg2=v2 %},{% url 'some-url-name' arg1 arg2 %}?name=jerry
自定义template tag和filter:
django寻找自定义tag和filter的目录是app_name/templatetags。
示例,自定义过滤器:创建packages,polls/templatetags/
# polls/templatetags/mytags.py
from django import template register = template.Library() #实例化一个注册器
@register.filter(name='Lower') #给过滤器起名为Lower,如果没有定义name,则名字为函数名 def lower(text): return text.lower() @register.filter def question_choice_count(question): return question.choice_set.count() @register.filter def question_choice_add(question, num): return question.choice_set.count() + int(num)
将过滤器增加到polls/templates/polls/index.html
{% load static %}
{% load mytags %}
<img src="{% static 'django.png' %}">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> --
{{ question|question_choice_count }} -- {{ question|question_choice_add:10 }}
{% endfor %}
</ul>
{% endif %}
模板扩展和包含: extends 、include
在mysite同级目录,创建templates、static目录。app、mysite、templates、static位于同一组目录,即项目mysite目录之下。
# templates/base.html 公共的模板 <html> <head> <title> {% block title %} {% endblock %} </title> {# 不同页面的标题是动态、需要变化的,使用block标签 #} {% include '_head_css_js.html' %} {# 套用或copy固定的头部css_js风格#} </head> <body> {% include '_header.html' %} {# 套用或copy固定的顶部html#} {% block content %} {# 不同页面中,需要变化的body部分,使用block标签#} {% endblock %} {% include '_footer.html' %} {# 套用或copy固定的底部html#} </body> </html> # templates/_header.html <div> this is header </div> # template/_footer.html <div> this is footer </div> # templates/_head_css_js.html # templates/index.html {% extends 'base.html' %} {# 套用base.html公共模板#} {% block content %} this is my self content {% endblock %} # templates/index2.html {% extends 'base.html' %} {% block content %} this is index index {% endblock %}
说明:extends是继承模板,必须写在第一行,然后自定义可以设置的block;include是导入一个模板片段到该位置。
对polls/templates/index.html,引用公共模板:
{% extends 'base.html' %}
{% load static %}
{% load mytags %}
{% block content %}
<img src="{% static 'django.png' %}">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> --
{{ question|question_choice_count }} -- {{ question|question_choice_add:10 }}
{% endfor %}
</ul>
{% endif %}
{% endblock %}
posted on 2014-06-16 18:49 myworldworld 阅读(200) 评论(0) 收藏 举报
浙公网安备 33010602011771号