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)    收藏  举报

导航