Django是一个开放源代码的Web应用框架,由Python写成。采用了MVT的软件设计模式,即模型Model,视图View和模板Template。
内容整理自自强学堂
数据迁移
导出的方法
比如我们有一个项目叫 mysite, 里面有一个 app 叫 blog ,我们想导出 blog 的所有数据。
python manage.py dumpdata blog > blog_dump.json
## 数据导入,不需要指定 appname
python manage.py loaddata blog_dump.json
多数据库连用
每个app都可以单独设置一个数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 # Database # https://docs.djangoproject.com/en/1.8/ref/settings/#databases DATABASES = { 'default' : { 'ENGINE' : 'django.db.backends.sqlite3' , 'NAME' : os.path.join(BASE_DIR, 'db.sqlite3' ), }, 'db1' : { 'ENGINE' : 'django.db.backends.postgresql_psycopg2' , 'NAME' : 'dbname1' , 'USER' : 'your_db_user_name' , 'PASSWORD' : 'yourpassword' , "HOST" : "localhost" , }, 'db2' : { 'ENGINE' : 'django.db.backends.postgresql_psycopg2' , 'NAME' : 'dbname2' , 'USER' : 'your_db_user_name' , 'PASSWORD' : 'yourpassword' , "HOST" : "localhost" , }, } # use multi-database in django # add by WeizhongTu DATABASE_ROUTERS = ['project_name.database_router.DatabaseAppsRouter' ] DATABASE_APPS_MAPPING = { # example: #'app_name' :'database_name' , 'app1' : 'db1' , 'app2' : 'db2' , }
使用指定的数据库来执行操作
在查询的语句后面用 using(dbname) 来指定要操作的数据库即可
# 查询 YourModel.objects.using ('db1' ).all() 或者 YourModel.objects.using ('db2' ).all() # 保存 或 删除 user_obj.save(using ='new_users' ) user_obj.delete(using ='legacy_users' )
多个数据库联用时数据导入导出
如果不是defalut(默认数据库)要在命令后边加 --database=数据库对应的settings.py中的名称 如: --database=db1 或 --database=db2
数据库同步(创建表)
python manage.py syncdb #同步默认的数据库,和原来的没有区别 #同步数据库 db1 (注意:不是数据库名是db1,是settings.py 中的那个db1,不过你可以使这两个名称相同,容易使用)python manage.py syncdb --database=db1
数据导出
python manage.py dumpdata app1 --database=db1 > app1 _fixture.jsonpython manage.py dumpdata app2 --database=db2 > app2 _fixture.jsonpython manage.py dumpdata auth > auth_fixture.json
数据库导入
python manage.py loaddata app1 _fixture.json --database=db1 python manage.py loaddata app2 _fixture.json --database=db2
Django 缓存系统 (调优)
缓存系统工作原理:
对于给定的网址,尝试从缓存中找到网址,如果页面在缓存中,直接返回缓存的页面,如果缓存中没有,一系列操作(比如查数据库)后,保存生成的页面内容到缓存系统以供下一次使用,然后返回生成的页面内容
{ 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', } }
也就是默认利用本地的内存来当缓存,速度很快。当然可能出来内存不够用的情况,其它的一些内建可用的 Backends 有
'django.core.cache.backends.db.DatabaseCache ''django.core.cache.backends.dummy.DummyCache ''django.core.cache.backends.filebased.FileBasedCache ''django.core.cache.backends.locmem.LocMemCache ''django.core.cache.backends.memcached.MemcachedCache ''django.core.cache.backends.memcached.PyLibMCCache '
利用文件系统来缓存:
CACHES = { 'default' : { 'BACKEND' : 'django.core.cache.backends.filebased.FileBasedCache' , 'LOCATION' : '/var/tmp/django_cache' , 'TIMEOUT' : 600, 'OPTIONS' : { 'MAX_ENTRIES' : 1000 } } }
利用数据库来缓存,利用命令创建相应的表:python manage.py createcachetable cache_table_name
CACHES = { 'default' : { 'BACKEND' : 'django.core.cache.backends.db.DatabaseCache' , 'LOCATION' : 'cache_table_name' , 'TIMEOUT' : 600, 'OPTIONS' : { 'MAX_ENTRIES' : 2000 } } }
一般流程
from django.shortcuts import renderdef index (request ): return render(request, 'index.html' , {'queryset' :queryset})
使用chache之后
from django.shortcuts import renderfrom django.views.decorators.cache import cache_page @cache_page(60 * 15 ) def index (request ): return render(request, 'index.html' , {'queryset' :queryset})
Memcached 是目前 Django 可用的最快的缓存,另外,Django 还可以共享缓存。
Django 生成静态页面 (调优)
如果网站的流量过大,每次访问时都动态生成,执行SQL语句,消耗大量服务器资源,这时候可以考虑生成静态页面。把静态页面存储到本地,下次就直接访问静态页面就好了。
from django.shortcuts import renderfrom django.template.loader import render_to_stringimport os def my_view (request ): context = {'some_key' : 'some_value' } static_html = '/path/to/static.html' if not os.path.exists(static_html): content = render_to_string('template.html' , context) with open (static_html, 'w' ) as static_file: static_file.write(content) return render(request, static_html)
当用户访问时,如果判断没有静态页面就自动生成静态页面,然后返回静态文件,当文件存在的时候就不再次生成。
但是一般情况下都不需要生成静态页面,因为Django 有缓存功能,使用 Django Cache(缓存)就相当于把生成生成静态页面,而且还有自动更新的功能,比如30分钟刷新一下页面内容。
Django安全
Django表单用在模板中的时候我们会加一句 {% csrf_token %}
Django国际化
开启国际化的支持,需要在settings.py文件中设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 MIDDLEWARE_CLASSES = ( ... 'django.middleware.locale.LocaleMiddleware' , ) LANGUAGE_CODE = 'en' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True LANGUAGES = ( ('en' , ('English' )), ('zh-cn' , ('中文简体' )), ('zh-tw' , ('中文繁體' )), ) #翻译文件所在目录,需要手工创建 LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale' ), ) TEMPLATE_CONTEXT_PROCESSORS = ( ... "django.core.context_processors.i18n" , )
生成需要翻译的文件: django-admin.py makemessages -l zh-cn django-admin.py makemessages -l zh-tw
手工翻译 locale 中的文本后,我们需要编译一下,这样翻译才会生效
django-admin .py compilemessages
Django session
Django完全支持也匿名会话,简单说就是使用跨网页之间可以进行通讯,比如显示用户名,用户是否已经发表评论。session框架让你存储和获取访问者的数据信息,这些信息保存在服务器上(默认是数据库中),以 cookies 的方式发送和获取一个包含 session ID的值,并不是用cookies传递数据本身。
启用session
编辑settings.py中的一些配置
MIDDLEWARE_CLASSES 确保其中包含以下内容
'django.contrib.sessions.middleware.SessionMiddleware',
INSTALLED_APPS 是包含
'django .contrib.sessions',
这些是默认启用的。如果你不用的话,也可以关掉这个以节省一点服务器的开销。
提示:您也可以配置使用比如 cache 来存储 session
在视图中使用 session
request.session 可以在视图中任何地方使用,它类似于python中的字典 session 默认有效时间为两周,可以在 settings.py 中修改默认值。
# 创建或修改 session : request.session [key] = value # 获取 session : request.session .get (key,default=None ) # 删除 session del request.session [key] # 不存在时报错
一个不让用户评价两次的例子
HttpResponse
from django.http import def post_comment (request, new_comment ): if request.session.get('has_commented' , False ): return HttpResponse("You've already commented." ) c = comments.Comment(comment=new_comment) c.save() request.session['has_commented' ] = True return HttpResponse('Thanks for your comment!' )
一个简化登录的验证
def login (request ): m = Member.objects.get(username=request.POST['username' ]) if m.password == request.POST['password' ]: request.session['member_id' ] = m.id return HttpResponse("You're logged in." ) else : return HttpResponse("Your username and password didn't match." ) def logout (request ): try : del request.session['member_id' ] except KeyError: pass return HttpResponse("You're logged out." )
Django传递数据给JS
有时候我们想把一个 list 或者 dict 传递给 javascript,处理后显示到网页上,比如要用 js 进行可视化的数据。
错误的使用方法
from __future__ import unicode_literalsfrom django.shortcuts import render def home (request ): List = ['自强学堂' , '渲染Json到模板' ] return render(request, 'home.html' , {'List' : List})
<script type ="text/javascript" > var List = {{ List }} ; alert(List);</script >
如果直接这么做,传递到 js 的时候,网页的内容会被转义,得到的格式会报错。
访问时会得到 Uncaught SyntaxError: Unexpected token ILLEGAL
需要注意两点:
views.py中返回的函数中的值要用 json.dumps()处理
在网页上要加一个 safe 过滤器。
正确的使用方法
from __future__ import unicode_literals import jsonfrom django.shortcuts import render def home (request ): List = ['自强学堂' , '渲染Json到模板' ] Dict = {'site' : '自强学堂' , 'author' : '涂伟忠' } return render(request, 'home.html' , { 'List' : json.dumps(List), 'Dict' : json.dumps(Dict) })
var List = {{ List|safe }}; alert(List);var Dict = {{ Dict|safe }}; alert(Dict);
Django遍历数组和字典的几种方法
遍历数组的三种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var List = {{ List|safe }}; //下面的代码把List的每一部分放到头部和尾部 $('#list').prepend(List[0]); $('#list').append(List[1]); console.log('--- 遍历 List 方法 1 ---') for(i in List){ console.log(List[i]);// i为索引 } console.log('--- 遍历 List 方法 2 ---') for (var i = List.length - 1; i >= 0; i--) { // 鼠标右键,审核元素,选择 console 可以看到输入的值。 console.log(List[i]); }; console.log('--- 同时遍历索引和内容,使用 jQuery.each() 方法 ---') $.each(List, function(index, item){ console.log(index+' '+item); });
遍历字典的方法和字典的取值
var Dict = {{ Dict|safe }}; console.log ("--- 两种字典的取值方式 ---" ) console.log (Dict['site']); console.log (Dict.author); console.log ("--- 遍历字典 ---" ); for(i in Dict) { console.log (i + Dict[i]); }
Django使用Ajax
一个简单的例子,获取单个数值。
jQuery的get方法
$.get('API' ,{'参数名1' :参数值1 ,'参数名2' :参数值2 },function (结果值 ) { $('接受返回数据的元素' ).html(结果值); $('接受返回数据的元素' ).val(结果值); })
# coding:utf-8 from __future__ import unicode_literalsimport json from django.http import HttpResponsefrom django.shortcuts import render def Add (request): a = request.GET ['a' ] b = request.GET ['b' ] a = int (a) b = int (b) return HttpResponse(str(a+b))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 {% extends 'Base.html' %} {% block content %} <p > 输入两个数字</p > <form action ="/add/" method ="get" > a: <input type ="text" id ="a" name ="a" > <br > b: <input type ="text" id ="b" name ="b" > <br > <p > result: <span id ="result" > </span > </p > <button type ="button" id ="sum" > 计算</button > </form > <script > $(document).ready(function(){ $('#sum').click(function(){ var a = $('#a').val(); var b = $('#b').val(); //使用很重要的jQuery的get方法 $.get('/add/',{'a':a,'b':b},function(ret){ $('#result').html(ret) }) }); }); </script > <img src ="/static/images/time.jpg" alt ="" / > {% endblock %}
较复杂的例子,传递列表和字典。
传递list
传递一个数组或字典到网页,由JS处理,再显示出来。关键是利用jQuery的 getJson
方法,核心代码如下:
$.getJSON('API' ,function (结果值 ) { $('#dict_result' ).append(ret.字典中的键名+'<br>' ); });
需要注意的是API可以这样来写,用 urls.py
中的 name
来获取是一个更好的方法!
from django.http import HttpResponse,JsonResponsedef ajax_list (request ): a = range (100 ) return JsonResponse(a,safe=False )def ajax_dict (request ): name_dict = {'twz' :'Love python and Django' ,'zqxt' :'I am teaching Django' } return JsonResponse(name_dict,safe=False )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <button id ='list' > Ajax加载字典</button > <p id ="list_result" > </p > <button id ='dict' > Ajax加载列表</button > <p id ="dict_result" > </p > <script > $(document ).ready(function ( ) { $('#list' ).click(function ( ) { $.getJSON('{% url ' ajax-list' %}' ,function (ret ) { for (var i = ret.length - 1 ; i >= 0 ; i--) { $('#list_result' ).append(' ' + ret[i]) }; }); }); $('#dict' ).click(function ( ) { $.getJSON('/ajax_dict/' ,function (ret ) { $('#dict_result' ).append(ret.zqxt+'<br>' ); }); }); });</script >
传递dict
def ajax_dict (request ): name_dict = {'twz' :'Love python and Django' ,'zqxt' :'I am teaching Django' } person_info_dict = [ {"name" :"xiaoming" , "age" :20 }, {"name" :"tuweizhong" , "age" :24 }, {"name" :"xiaoli" , "age" :33 } ] return JsonResponse(person_info_dict,safe=False )
<button id ='dict' > Ajax加载字典</button > <p id ="dict_result" > </p > <script > $(document ).ready(function ( ) { $('#dict' ).click(function ( ) { $.getJSON('{% url ' ajax-dict' %}' ,function (ret ) { $.each(ret,function (i,item ) { $('#list_result' ).append(i+' ' +item.name+' ' +item.age+'</br>' ); }); }); }); });</script >
更复杂的例子,Ajax加载图片。
图片是放置在与APP目录同层次的common_static文件夹的pics文件夹之中的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <p > 请输入</p > <form action ="/add/" method ="get" > color: <input type ="text" id ="color" name ="color" value ="red" > <br > number: <input type ="text" id ="number" name ="number" value ="1" > <br > <p > result: <span id ='result' > </span > </p > <button type ="button" id ='sum' > 提交</button > <img src ="" alt ="" > </form > <script src ="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.min.js" > </script > <script > $(document ).ready(function ( ) { $("#sum" ).click(function ( ) { var color = $("#color" ).val(); var number = $("#number" ).val(); $.get("{% url 'get-pic' %}" , { 'color' : color, 'number' : number }, function (ret ) { $('#result' ).html('' ) $.each(ret, function (index, item ) { $('#result' ).append('<img src="/static/pics/' + item + '">' ); }) }) }); });</script >
def get_pic(request): color = request.GET.get ('color' ) number = request.GET.get ('number' ) name = '{}_{}' .format(color, number) print "!" *100 # 过滤出符合要求的图片,假设是以输入的开头的都返回 result_list = filter(lambda x: x.startswith(name), PICS) print 'result_list' , result_list return HttpResponse( json.dumps(result_list), content_type ='application/json' )
注意filter
和format
的使用
from django.conf.urls import patterns, include, urlfrom django.contrib import admin admin.autodiscover() urlpatterns = patterns('' , url(r'^$' , 'tools.views.index' , name='home' ), url(r'^get_pic/$' , 'tools.views.get_pic' , name='get-pic' ), url(r'^admin/' , include(admin.site.urls)), )
Django Ajax CSRF认证
CSRF通过伪装来自受信任用户的请求来利用受信任的网站
Django 中自带了 防止CSRF攻击的功能,但是一些新手不知道如何使用,给自己编程带来了麻烦。常常会出现下面django csrf token missing or incorrect 的错误。
GET 请求不需要 CSRF 认证,POST 请求需要正确认证才能得到正确的返回结果。一般在POST表单中加入
完整代码如下
<form method ="POST" action ="/post-url/" > {% csrf_token %} <input name ='zqxt' value ="自强学堂学习Django技术" > </form >
使用Ajax调用的时候,就要麻烦一些。需要注意以下几点:
在视图中使用 render (而不要使用 render_to_response)
使用 jQuery 的 ajax 或者 post 之前 加入这个 js 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 jQuery(document ).ajaxSend(function (event, xhr, settings ) { function getCookie (name ) { var cookieValue = null ; if (document .cookie && document .cookie != '' ) { var cookies = document .cookie.split(';' ); for (var i = 0 ; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); if (cookie.substring(0 , name.length + 1 ) == (name + '=' )) { cookieValue = decodeURIComponent (cookie.substring(name.length + 1 )); break ; } } } return cookieValue; } function sameOrigin (url ) { var host = document .location.host; var protocol = document .location.protocol; var sr_origin = '//' + host; var origin = protocol + sr_origin; return (url == origin || url.slice(0 , origin.length + 1 ) == origin + '/' ) || (url == sr_origin || url.slice(0 , sr_origin.length + 1 ) == sr_origin + '/' ) || !(/^(\/\/|http:|https:).*/ .test(url)); } function safeMethod (method ) { return (/^(GET|HEAD|OPTIONS|TRACE)$/ .test(method)); } if (!safeMethod(settings.type) && sameOrigin(settings.url)) { xhr.setRequestHeader("X-CSRFToken" , getCookie('csrftoken' )); } });
更为优雅简洁的代码(不能写在 *.js
中,要直接写在模板文件中 ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 jQuery(document ).ajaxSend(function (event, xhr, settings ) { function getCookie (name ) { var cookieValue = null ; if (document .cookie && document .cookie != '' ) { var cookies = document .cookie.split(';' ); for (var i = 0 ; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); if (cookie.substring(0 , name.length + 1 ) == (name + '=' )) { cookieValue = decodeURIComponent (cookie.substring(name.length + 1 )); break ; } } } return cookieValue; } function sameOrigin (url ) { var host = document .location.host; var protocol = document .location.protocol; var sr_origin = '//' + host; var origin = protocol + sr_origin; return (url == origin || url.slice(0 , origin.length + 1 ) == origin + '/' ) || (url == sr_origin || url.slice(0 , sr_origin.length + 1 ) == sr_origin + '/' ) || !(/^(\/\/|http:|https:).*/ .test(url)); } function safeMethod (method ) { return (/^(GET|HEAD|OPTIONS|TRACE)$/ .test(method)); } if (!safeMethod(settings.type) && sameOrigin(settings.url)) { xhr.setRequestHeader("X-CSRFToken" , getCookie('csrftoken' )); } });
```` csrfmiddlewaretoken: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 代码集合 ```html <script src ="/static/jquery.min.js" > </script > <script > /* 自强学堂 学习更多IT技术 http: */ $('document' ).ready(function ( ) { $.ajaxSetup({ data: { csrfmiddlewaretoken: ' {{ csrf_token }} ' }, }); }) function select_drug ( ) { var drug = document .forms[0 ].drug; var drugs = "" ; var i; for (i = 0; i < drug.length; i++) { if (drug[i].checked) { drugs = drugs + drug[i].value + " " ; } } $.post('{% url "exam2014" %}' , { 'drugs' : drugs }, function (ret ) { $('#result' ).html(ret); }) } </script >
Django Sitemap 站点地图
Django 中自带了 sitemap框架,用来生成 xml 文件 sitemap 很重要 ,可以用来通知搜索引擎页面的地址,页面的重要性,帮助站点得到比较好的收录 。
自强学堂参考链接
单元测试技术
Django中有完善的单元测试 ,我们可以对开发的每一个功能进行单元测试,这样只要运行一个命令 python manage.py test,就可以测试功能是否正常。
Python中的单元测试
关键格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import unittestdef 测试函数(参数值1 ,参数值2 ,.... ): 函数体class 测试类名(unittest.TestCase ): def 测试函数名(self ): self.assertEqual(测试函数(参数值1 ,参数值2 ,....),目标对比参数1 ) def 测试函数名1(self ): self.assertEqual(测试函数(参数值1 ,参数值2 ,....),目标对比参数2 ) def 测试函数名2(self ): self.assertEqual(测试函数(参数值1 ,参数值2 ,....),目标对比参数3 ) if __name__ == '__main__' : unittest.main()
实例:测试一个除法功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import unittest def division_funtion(x , y ) : return x / y class TestDivision(unittest .TestCase) : def test_int(self ) : self.assert Equal(division_funtion (9, 3) , 3 ) def test_int2(self ) : self.assert Equal(division_funtion (9, 4) , 2.25 ) def test_float(self ) : self.assert Equal(division_funtion (4.2, 3) , 1.4 ) if __name__ == '__main__': unittest.main()
有两个错误9/4=2!=2.25 以及4.2/3=1.4000000000000001 != 1.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 C:\Users\Tony\Desktop\VueTest>python UniteTest.py.FF ====================================================================== FAIL: test_int1 (__main__ .TestDivision) ---------------------------------------------------------------------- Traceback (most recent call last): File "UniteTest.py", line 13, in test_int1 self.assertEqual(division_function(9,4),2.25) AssertionError: 2 != 2.25 ====================================================================== FAIL: test_int2 (__main__ .TestDivision) ---------------------------------------------------------------------- Traceback (most recent call last): File "UniteTest.py", line 16, in test_int2 self.assertEqual(division_function(4.2,3),1.4) AssertionError: 1.4000000000000001 != 1.4 ---------------------------------------------------------------------- Ran 3 tests in 0.002s FAILED (failures=2)
设置浮点运算,保留到小数点后六位。
def division_funtion (x, y ): return round (float (x) / y, 6 )
完全没有错误了
C:\Users\Tony\Desktop\VueTest>python UniteTest.py ... ------------------------------------------------- Ran 3 tests in 0.001s OK
Django中的单元测试
简单测试例子
from django.test import TestCase from myapp.models import Animalclass AnimalTestCase(TestCase) : def setUp(self ) : Animal . objects.create(name="lion" , sound="roar" ) Animal . objects.create(name="cat" , sound="meow" ) def test_animals_can_speak(self ) : "" "Animals that can speak are correctly identified" "" lion = Animal . objects.get(name="lion" ) cat = Animal . objects.get(name="cat" ) self.assert Equal(lion .speak () , 'The lion says "roar" ') self.assert Equal(cat .speak () , 'The cat says "meow" ')
Django上下文渲染器
简介
有时候我们想把一个变量在多个模板之间共用,这时候就可以用 Django 上下文渲染器。
TEMPLATES = [ { 'BACKEND' : 'django .template.backends.django.DjangoTemplates' , 'DIRS' : [] , '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', ], }, }, ]
这里的 context_processors 中放了一系列的渲染器 ,上下文渲染器其实就是函数返回字典 ,这些值可以用在模板中。 request函数就是在返回一个字典 ,每一个模板中都可以使用这个字典中提供的 request 变量。
比如 在template 中 获取当前访问的用户的用户名:
User Name : {{ request.user.username }}
动手写个上下文渲染器
1、新建一个项目,基于 Django 1.9,我们新建了 zqxt 项目和 blog 这个应用。把 blog 这个app 加入到 settings.py 中。
2、我们在 zqxt/zqxt/ 这个目录下(与settings.py 在一起)新建一个 context_processor.py
from django.conf import settings as original_settingsdef settings (request ): return {'settings' : original_settings}def ip_address (request ): return {'ip_address' : request.META['REMOTE_ADDR' ]}
3、我们把新建的两个 上下文渲染器 加入到 settings.py 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 TEMPLATES = [ { 'BACKEND' : 'django .template.backends.django.DjangoTemplates' , 'DIRS' : [] , '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', 'zqxt .context_processor.settings', 'zqxt .context_processor.ip_address', ], }, }, ]
from django.shortcuts import renderdef index (reuqest ): return render(reuqest, 'blog/index.html' ) def columns (request ): return render(request, 'blog/columns.html' )
5、新建两个模板文件,放在 zqxt/blog/template/blog/ 中
index.html <h1 > Blog Home Page</h1 > DEBUG: {{ settings.DEBUG }} ip: {{ ip_address }}
columns.html
<h1 > Blog Columns</h1 > DEBUG: {{ settings.DEBUG }} ip: {{ ip_address }}
from django.conf.urls import include, urlfrom django.contrib import adminfrom blog import views as blog_views urlpatterns = [ url(r'^blog_home/$' , blog_views.index), url(r'^blog_columns/$' , blog_views.columns), url(r'^admin/' , include(admin.site.urls)), ]
7、打开开发服务器并访问这两个网址就能够查看到相同的数据了
Django 通用视图
通用视图就是在view中创造类,利用类本身的方法和继承自父类的方法来完成相关的功能。
Base Views
django.views.generic.base.View
这个类是通用类的基类,其它类都是继承自这个类,一般不会用到这个类,感觉用函数更简单些。 在urls.py中使用类视图的时候都是调用它的 .as_view()
函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from django.http import HttpResponsefrom django.views.generic import View class MyView (View ): def get (self, request, *args, **kwargs ): return HttpResponse('Hello, World!' ) from django.conf.urls import patterns, url from myapp.views import MyView urlpatterns = patterns('' , url(r'^mine/$' , MyView.as_view(), name='my-view' ), )
django.views.generic.base.TemplateView
在 get_context_data()
函数中,可以传一些 额外内容 到 模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from django.views.generic.base import TemplateView from articles.models import Article class HomePageView (TemplateView ): template_name = "home.html" def get_context_data (self, **kwargs ): context = super (HomePageView, self).get_context_data(**kwargs) context['latest_articles' ] = Article.objects.all ()[:5 ] return context from django.conf.urls import patterns, url from myapp.views import HomePageView urlpatterns = patterns('' , url(r'^$' , HomePageView.as_view(), name='home' ), )
django.views.generic.base.RedirectView
用来进行跳转, 默认是永久重定向(301),可以直接在urls.py中使用,非常方便:
from django.conf.urls import patterns, urlfrom django.views.generic.base import RedirectView urlpatterns = patterns('' , url(r'^go-to-django/$' , RedirectView.as_view(url='http://djangoproject.com' ), name='go-to-django' ), url(r'^go-to-ziqiangxuetang/$' , RedirectView.as_view(url='http://www.ziqiangxuetang.com' ,permant=False ), name='go-to-zqxt' ), )
另外的用法,可以用来记录文章的点击次数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from django.shortcuts import get_object_or_404from django.views.generic .base import RedirectView from articles.models import Article class ArticleCounterRedirectView (RedirectView ): url = ' permanent = False query_string = True pattern_name = 'article-detail' def get_redirect_url(self, *args, **kwargs): If url is not set , get_redirect_url() tries to reverse the pattern_name using what was captured in the URL (both named and unnamed groups are used). article = get_object_or_404(Article , pk=kwargs['pk']) article.update_counter() return super(ArticleCounterRedirectView , self).get_redirect_url(*args, **kwargs) from django.conf.urls import patterns, urlfrom django.views.generic .base import RedirectView from article.views import ArticleCounterRedirectView , ArticleDetail urlpatterns = patterns('', url(r'^counter/(?P<pk>\d+)/$', ArticleCounterRedirectView .as_view(), name='article-counter'), url(r'^details/(?P<pk>\d+)/$', ArticleDetail .as_view(), name='article-detail'), )
Generic Display View
参考链接
django.views.generic.detail.DetailView
DetailView有以下方法
1.dispatch()
根据发送给view的请求类型分配post()方法或者get()方法,一般在默认情况下,带head的请求都是分配给get()方法处理的,但是如果你想向view发送带head的请求,而且在view处理请求的不是get()方法,可以重写get()方法。
2.http_method_not_allowed()
如果发送给view的方法是django不支持的,那么就会执行这个函数,它会返回django支持的http请求方法
3.get_template_names()
返回一个模板名字的列表,第一个找到的要渲染的目标模会被渲染
4.get_slug_field()
返回一个slug field的名字。然后slug会根据这个名字去查阅slug filed的值。
5.get_queryset()
返回一个QuerySet,包含了要展示在页面上的数据。
6.get_object(queryset=None)
返回单个对象,用于这个view将要展示的数据,如果返回的queryset是有效的,就用这个queryset,否则调用get_queryset()方法,去寻找一个pk_url_kwarg主键参数,如果有这个主键参数,就以此为基础去寻找相关的值,否则就用slug field方法去找相关的值
7.get_context_object_name(obj)
返回一个context variable name,包含页面要操作的数据。当 context_object_name没有被设置的时候,会自动使用model的小写作为 context_object_name,例如Article,article。
8.get_context_data(**kwargs)
返回一个上下文数据(context data),作为列表展示的对象。
9.get()
10.render_to_response()
返回一个self.response_class对象,如果获得任何一个keyword参数,那么keyword参数就会被传递给self.response_class的构造函数。
自动生成当前时间,使用DetailView将额外的数据传输到页面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from django.views.generic.detail import DetailViewfrom django.utils import timezone from articles.models import Article class ArticleDetailView (DetailView ): model = Article template_name = 'article_detail.html' def get_context_data (self, **kwargs ): context = super (ArticleDetailView, self).get_context_data(**kwargs) context['now' ] = timezone.now() return context from django.conf.urls import url from article.views import ArticleDetailView urlpatterns = [ url(r'^(?P<slug>[-_\w]+)/$' , ArticleDetailView.as_view(), name='article-detail' ), ]
article_detail.html文件新建在app下的templates文件夹里面
<h1 > 标题:{{ object.title }} </h1 > <p > 内容:{{ object.content }} </p > <p > 发表人: {{ object.reporter }} </p > <p > 发表于: {{ object.pub_date |date }} </p > <p > 日期: {{ now |date }} </p >
django.views.generic.list.ListView
ListView有以下几种方法: 1. dispatch()
2. http_method_not_allowed()
3. get_template_names()
4. get_queryset()
5. get_context_object_name()
6. get_context_data()
7. get()
8. render_to_response()
view.py文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from django.views.generic.list import ListViewfrom django.utils import timezone from articles.models import Article class ArticleListView (ListView ): model = Article def get_context_data (self, **kwargs ): context = super (ArticleListView, self).get_context_data(**kwargs) context['now' ] = timezone.now() return context from django.conf.urls import url from article.views import ArticleListView urlpatterns = [ url(r'^$' , ArticleListView.as_view(), name='article-list' ), ]
html文件
<h1 > 文章列表</h1 > <ul > {% for article in object_list %} <li > {{ article.pub_date|date }} - {{ article.headline }} </li > {% empty %} <li > 抱歉,目前还没有文章。</li > {% endfor %} </ul >