腊月的季节

django初步

命令使用

1、创建django项目:django-admin startproject djangodemo1
2、创建django应用:python manage.py startapp login
3、自动创建表:python manage.py makemigrations,python manage.py migrate
4、使用开发服务器:python manage.py runserver
5、清空数据库:python manage.py flush
6、创建超级管理员:python manage.py createsuperuser
7、导出数据:python manage.py dumpdata appname>appname.json
8、导入数据:python manage.py loaddata appname.json
9、项目环境终端python manage.py shell
10、数据库命令行python manage.py dbshell
11、更多命令python manage.py
12、新建项目后生成一个文件夹主要是项目的设置文件
13、新建项目,新建应用
14、定义视图函数(访问页面时的内容)

django的get,post方法与express的get,post方法不同

1
2
3
4
5
def add(request):
a=request.GET['a']
b=request.GET['b']
c=int(a)+int(b)
return HttpResponse(str(c))

url匹配参数与express不同

1
2
3
def add2(request,a,b):
c=int(a)+int(b)
return HttpResponse(str(c))

巧妙访问网页

1
2
3
4
不带参数的:
{% url 'name' %}
带参数的:参数可以是变量名
{% url 'name' 参数 %}

模板:模板中的for循环,条件判断,常用的标签,过滤器的使用。

for循环示例:

1
2
3
4
5
6
7
8
列表类型:
{% for i in TutorialList %}
{{ i }}
{% endfor %}
字典类型:
{% for key, value in info_dict.items %}
{{ key }}: {{ value }}
{% endfor %}

if条件判断示例:

1
2
3
{% for item in List %}
{{ item }}{% if not forloop.last%},{% endif %}
{% endfor %}

for循环常用循环位置判断:

变量 描述
forloop.counter 索引从 1 开始算
forloop.counter0 索引从 0 开始算
forloop.revcounter 索引从最大长度到 1
forloop.revcounter0 索引从最大长度到 0
forloop.first 当遍历的元素为第一项时为真
forloop.last 当遍历的元素为最后一项时为真
forloop.parentloop 用在嵌套的 for 循环中,获取上一层 for 循环的 forloop

当列表中可能为空值时用 for empty

1
2
3
4
5
6
7
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% empty %}
<li>抱歉,列表为空</li>
{% endfor %}
</ul>

模板中的逻辑操作:

1
2
3
4
5
6
7
8
9
10
11
{% if var >= 90 %}
成绩优秀,自强学堂你没少去吧!学得不错
{% elif var >= 80 %}
成绩良好
{% elif var >= 70 %}
成绩一般
{% elif var >= 60 %}
需要努力
{% else %}
不及格啊,大哥!多去自强学堂学习啊!
{% endif %}

and,or,not,in,not in也可以在模板中使用

1
2
3
4
5
{% if num <= 100 and num >= 0 %}
num在0到100之间
{% else %}
数值不在范围之内!
{% endif %}

判断用户是否登录

1
2
3
4
5
{% if request.user.is_authenticated %}
{{ request.user.username }},您好!
{% else %}
请登陆,这里放登陆链接
{% endif %}

数据库模型

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
from django.db import models

class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
python manage.py syncdb # 进入 manage.py 所在的那个文件夹下输入这个命令

注意:Django 1.7 及以上的版本需要用以下命令
python manage.py makemigrations
python manage.py migrate
$ python manage.py shell

>>> from people.models import Person
>>> Person.objects.create(name="WeizhongTu", age=24)
<Person: Person object>
>>>
from django.db import models


class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()

def __unicode__(self):
# 在Python3中使用 def __str__(self)
return self.name

新建一个对象的方法有以下几种:
1.Person.objects.create(name=name,age=age)
2.p = Person(name=”WZ”, age=23)
p.save()
3.p = Person(name=”TWZ”)
p.age = 23
p.save()
4.Person.objects.get_or_create(name=”WZT”, age=23)
这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False, 新建时返回的是True, 已经存在时返回False.

获取对象有以下方法:
1.Person.objects.all()
2.Person.objects.all()[:10] 切片操作,获取10个人,不支持负索引,切片可以节约内存
3.Person.objects.get(name=name)
1.get是用来获取一个对象的,如果需要获取满足条件的一些人,就要用到filter
2.Person.objects.filter(name=”abc”) # 等于
Person.objects.filter(name__exact=”abc”) 名称严格等于 “abc” 的人
3.Person.objects.filter(name__iexact=”abc”) # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件

4.Person.objects.filter(name__contains=”abc”) # 名称中包含 “abc”的人
5.Person.objects.filter(name__icontains=”abc”) #名称中包含 “abc”,且abc不区分大小写

6.Person.objects.filter(name__regex=”^abc”) # 正则表达式查询
7.Person.objects.filter(name__iregex=”^abc”)# 正则表达式不区分大小写

filter是找出满足条件的,当然也有排除符合某条件的
8.Person.objects.exclude(name__contains=”WZ”) # 排除包含 WZ 的Person对象
9.Person.objects.filter(name__contains=”abc”).exclude(age=23) # 找出名称含有abc, 但是排除年龄是23岁的

自定义Field

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#coding:utf-8
from django.db import models


class CompressedTextField(models.TextField):
"""
model Fields for storing text in a compressed format (bz2 by default)
"""

def from_db_value(self, value, expression, connection, context):
if not value:
return value
try:
return value.decode('base64').decode('bz2').decode('utf-8')
except Exception:
return value

def to_python(self, value):
if not value:
return value
try:
return value.decode('base64').decode('bz2').decode('utf-8')
except Exception:
return value

def get_prep_value(self, value):
if not value:
return value
try:
value.decode('base64')
return value
except Exception:
try:
return value.encode('utf-8').encode('bz2').encode('base64')
except Exception:
return value
做一个列表保存到数据库
from django.db import models
import ast

class ListField(models.TextField):
__metaclass__ = models.SubfieldBase
description = "Stores a python list"

def __init__(self, *args, **kwargs):
super(ListField, self).__init__(*args, **kwargs)

def to_python(self, value):
if not value:
value = []

if isinstance(value, list):
return value

return ast.literal_eval(value)

def get_prep_value(self, value):
if value is None:
return value

return unicode(value) # use str(value) in Python 3

def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_db_prep_value(value)

数据表修改

South工具
(1)QuerySet创建对象的方法
(2)获取对象的方法
(3)QuerySet是可迭代的
(4)QuerySet是可以用pickle序列化到硬盘再读取出来
(5)QuerySet查询结果排序
(6)QuerySet支持链式查询
(7)QuerySet不支持负索引
(8)QuerySet重复的问题,使用.distinct()去重

django后台

1
2
3
4
5
6
7
8
9
10
11
12
# coding:utf-8
from django.db import models


class Article(models.Model):
title = models.CharField(u'标题', max_length=256)
content = models.TextField(u'内容')

pub_date = models.DateTimeField(u'发表时间', auto_now_add=True, editable = True)
update_time = models.DateTimeField(u'更新时间',auto_now=True, null
def __unicode__(self):# 在Python3中用 __str__ 代替 __unicode__
return self.title=True)

django表单

GET请求:
前台:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
<body>
<p>请输入两个数字</p>


<form action="/add/" method="get">
a: <input type="text" name="a"> <br>
b: <input type="text" name="b"> <br>

<input type="submit" value="提交">
</form>


</body>
</html>

后台:

1
2
3
4
5
6
7
8
9
10
11
12
from django.http import HttpResponse
from django.shortcuts import render

def index(request):
return render(request, 'index.html')

def add(request):
a = request.GET['a']
b = request.GET['b']
a = int(a)
b = int(b)
return HttpResponse(str(a+b))

POST请求:
forms.py

1
2
3
4
5
from django import forms

class AddForm(forms.Form):
a = forms.IntegerField()
b = forms.IntegerField()

views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# coding:utf-8
from django.shortcuts import render
from django.http import HttpResponse

# 引入我们创建的表单类
from .forms import AddForm

def index(request):
if request.method == 'POST':# 当提交表单时

form = AddForm(request.POST) # form 包含提交的数据

if form.is_valid():# 如果提交的数据合法
a = form.cleaned_data['a']
b = form.cleaned_data['b']
return HttpResponse(str(int(a) + int(b)))

else:# 当正常访问时
form = AddForm()
return render(request, 'index.html', {'form': form})

index.html

1
2
3
4
5
<form method='post'>
{% csrf_token %}
{{ form }}
<input type="submit" value="提交">
</form>

urls.py

1
2
3
4
5
6
7
8
9
10
from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
# 注意下面这一行
url(r'^$', 'tools.views.index', name='home'),
url(r'^admin/', include(admin.site.urls)),
)

django配置

1
2
3
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

这里用到了python中一个神奇的变量 file 这个变量可以获取到当前文件(包含这个代码的文件)的路径。os.path.dirname(file) 得到文件所在目录,再来一个os.path.dirname()就是目录的上一级,BASE_DIR 即为 项目 所在目录。我们在后面的与目录有关的变量都用它,这样使得移植性更强。

1
2
3
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True

DEBUG=True 时,如果出现 bug 便于我们看见问题所在,但是部署时最好不要让用户看见bug的详情,可能一些不怀好心的人攻击网站,造成不必要的麻烦。

1
ALLOWED_HOSTS = ['*.besttome.com','www.ziqiangxuetang.com']

ALLOWED_HOSTS 允许你设置哪些域名可以访问,即使在 Apache 或 Nginx 等中绑定了,这里不允许的话,也是不能访问的。
当 DEBUG=False 时,这个为必填项,如果不想输入,可以用 ALLOW_HOSTS = [‘*’] 来允许所有的。

1
2
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR,'static')

static 是静态文件所有目录,比如 jquery.js, bootstrap.min.css 等文件。
一般来说我们只要把静态文件放在 APP 中的 static 目录下,部署时用 python manage.py collectstatic 就可以把静态文件收集到(复制到) STATIC_ROOT 目录,但是有时我们有一些共用的静态文件,这时候可以设置 STATICFILES_DIRS 另外弄一个文件夹,如下:

1
2
3
4
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "common_static"),
'/var/www/static/',
)

这样我们就可以把静态文件放在 common_static 和 /var/www/static/中了,Django也能找到它们。

1
2
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

media文件夹用来存放用户上传的文件,与权限有关,详情见 Django 静态文件Django 部署

1
2
3
4
5
6
7
8
9
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR,'templates').replace('\\', '/'),
os.path.join(BASE_DIR,'templates2').replace('\\', '/'),
],
'APP_DIRS': True,
]

这样 就可以把模板文件放在 templates 和 templates2 文件夹中了。

Django静态文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_URL = '/static/'

# 当运行 python manage.py collectstatic 的时候
# STATIC_ROOT 文件夹 是用来将所有STATICFILES_DIRS中所有文件夹中的文件,以及各app中static中的文件都复制过来
# 把这些文件放到一起是为了用apache等部署的时候更方便
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')

# 其它 存放静态文件的文件夹,可以用来存放项目中公用的静态文件,里面不能包含 STATIC_ROOT
# 如果不想用 STATICFILES_DIRS 可以不用,都放在 app 里的 static 中也可以
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "common_static"),
'/path/to/others/static/', # 用不到的时候可以不写这一行
)

# 这个是默认设置,Django 默认会在 STATICFILES_DIRS中的文件夹 和 各app下的static文件夹中找文件
# 注意有先后顺序,找到了就不再继续找了
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder"
)

自己分配静态文件

1
2
3
4
5
6
7
# static files
import os
from django.conf.urls.static import static
from django.conf import settings
if settings.DEBUG:
media_root = os.path.join(settings.BASE_DIR,'media2')
urlpatterns += static('/media2/', document_root=media_root)

1
2
3
4
5
6
from django.conf.urls.static import static

urlpatterns = patterns('',
url(r'^$', 'app.views.index', name='index'),
url(r'^admin/', include(admin.site.urls)),
) + static('/media2/', document_root=media_root)

django部署

apache部署和nginx部署

文本数据导入

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
#!/usr/bin/env python
#coding:utf-8

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

'''
Django 版本大于等于1.7的时候,需要加上下面两句
import django
django.setup()
否则会抛出错误 django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
'''

import django
if django.VERSION >= (1, 7):#自动判断版本
django.setup()


def main():
from blog.models import Blog
f = open('oldblog.txt')
for line in f:
title,content = line.split('****')
Blog.objects.create(title=title,content=content)
f.close()

if __name__ == "__main__":
main()
print('Done!')

json文本数据导入

python manage.py dumpdata fixture.json导出
python manage.py loaddata fixture.json导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

def main():
from blog.models import Blog
f = open('oldblog.txt')

BlogList = []
for line in f:
parts = line.split('****')
BlogList.append(Blog(title=parts[0], content=parts[1]))

f.close()

# 以上四行 也可以用 列表解析 写成下面这样
# BlogList = [Blog(title=line.split('****')[0], content=line.split('****')[1]) for line in f]

Blog.objects.bulk_create(BlogList)

if __name__ == "__main__":
main()
print('Done!')

django数据迁移

python manage.py dumpdata [appname] > appname_data.json数据库导出
python manage.py loaddata blog_dump.json数据导入
mysql

1
2
3
4
5
6
7
# 导出数据库 zqxt 到 zqxt.sql 文件中
mysqldump -u username -p --database zqxt > zqxt.sql

# 导入数据库到 新的服务器
mysql -u username -p
输入密码进入 MySQL 命令行
> source /path/to/zqxt.sql

django多数据库联用

(1)每个app都可以单独设置一个数据库
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
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',
}

在project_name文件夹中存放database_route.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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# -*- coding: utf-8 -*-
from django.conf import settings

DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING


class DatabaseAppsRouter(object):
"""
A router to control all database operations on models for different
databases.

In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
will fallback to the `default` database.

Settings example:

DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
"""

def db_for_read(self, model, **hints):
""""Point all read operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None

def db_for_write(self, model, **hints):
"""Point all write operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None

def allow_relation(self, obj1, obj2, **hints):
"""Allow any relation between apps that use the same database."""
db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
if db_obj1 and db_obj2:
if db_obj1 == db_obj2:
return True
else:
return False
return None

def allow_syncdb(self, db, model):
"""Make sure that apps only appear in the related database."""

if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(model._meta.app_label) == db
elif model._meta.app_label in DATABASE_MAPPING:
return False
return None

2、使用指定的数据库来进行操作

1
2
3
4
5
6
7
# 查询
YourModel.objects.using('db1').all()
或者 YourModel.objects.using('db2').all()

# 保存 或 删除
user_obj.save(using='new_users')
user_obj.delete(using='legacy_users')

3、多个数据库联用时数据导入导出
数据库同步

1
2
3
4
5
6
7
8
9
10
11
python manage.py syncdb #同步默认的数据库,和原来的没有区别

#同步数据库 db1 (注意:不是数据库名是db1,是settings.py中的那个db1,不过你可以使这两个名称相同,容易使用)
python manage.py syncdb --database=db1
数据导出
python manage.py dumpdata app1 --database=db1 > app1_fixture.json
python manage.py dumpdata app2 --database=db2 > app2_fixture.json
python 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缓存cache

settings.py

1
2
3
4
5
{
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
}
}

利用文件系统来缓存

1
2
3
4
5
6
7
8
9
10
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
'TIMEOUT': 600,
'OPTIONS': {
'MAX_ENTRIES': 1000
}
}
}

利用数据库来缓存

1
2
3
4
5
6
7
8
9
10
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'cache_table_name',
'TIMEOUT': 600,
'OPTIONS': {
'MAX_ENTRIES': 2000
}
}
}

django缓存系统实例

1
2
3
4
5
from django.shortcuts import render
def index(request):
# 读取数据库等 并渲染到网页
# 数据库获取的结果保存到 queryset 中
return render(request, 'index.html', {'queryset':queryset})

像这样每次访问都要读取数据库,一般的小网站没什么问题,当访问量非常大的时候,就会有很多次的数据库查询,肯定会造成访问速度变慢,服务器资源占用较多等问题。

1
2
3
4
5
6
7
from django.shortcuts import render
from django.views.decorators.cache import cache_page

@cache_page(60 * 15) # 秒数,这里指缓存 15 分钟,不直接写900是为了提高可读性
def index(request):
# 读取数据库等 并渲染到网页
return render(request, 'index.html', {'queryset':queryset})

django生成静态网页

views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from django.shortcuts import render
from django.template.loader import render_to_string
import 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)

上面的例子中,当用户访问时,如果判断没有静态页面就自动生成静态页面,然后返回静态文件,当文件存在的时候就不再次生成。
也可以用一个文件夹,比如在project下建一个 static_html 文件夹,把生成的静态文件都放里面,让用户像访问静态文件那样访问页面。

django国际化

(1)开启国际化支持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
28
29
30
31
32
33
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', ('中文繁體')),
)
1.9版本以上
LANGUAGES = (
('en', ('English')),
('zh-hans', ('中文简体')),
('zh-hant', ('中文繁體')),
)

#翻译文件所在目录,需要手工创建
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)

TEMPLATE_CONTEXT_PROCESSORS = (
...
"django.core.context_processors.i18n",
)

(2)生成需要的编译的文件

1
2
python manage.py makemessages -l zh-cn
python manage.py makemessages -l zh-tw

(3)编译

1
python manage.py compilemessages

django session

settings.py配置

1
'django.contrib.sessions.middleware.SessionMiddleware',

在视图中使用session

1
2
3
4
5
6
# 创建或修改 session:
request.session[key] = value
# 获取 session:
request.session.get(key,default=None)
# 删除 session
del request.session[key] # 不存在时报错

session例子:不让用户评论两次

1
2
3
4
5
6
7
8
9
from django.http import HttpResponse

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!')

一个简化的登录认证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

一、页面加载完成后(ajax)
二、直接在视图函数(一次性渲染,同一次请求)
views.py

1
2
3
4
5
6
from __future__ import unicode_literals
from django.shortcuts import render

def home(request):
List = ['自强学堂', '渲染Json到模板']
return render(request, 'home.html', {'List': List})

home.html

1
2
3
4
<script type="text/javascript">
var List = {{ List }};
alert(List);
</script>

会报错
需要注意两点:

  1. views.py中返回的函数中的值要用 json.dumps()处理
  2. 在网页上要加一个 safe 过滤器
    views.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # -*- coding: utf-8 -*-

    from __future__ import unicode_literals

    import json
    from 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)
    })

home.html 只给出了js的核心部分

1
2
3
4
//列表
var List = {{ List|safe }};
//字典
var Dict = {{ Dict|safe }};

django中间件

1、比如我们要做一个拦截器,发现有恶意访问网站的人,就拦截他。

1
2
3
4
5
6
#项目 zqxt 文件名 zqxt/middleware.py

class BlockedIpMiddleware(object):
def process_request(self, request):
if request.META['REMOTE_ADDR'] in getattr(settings, "BLOCKED_IPS", []):
return http.HttpResponseForbidden('<h1>Forbidden</h1>')

这里的代码的功能就是 获取当前访问者的 IP (request.META[‘REMOTE_ADDR’]),如果这个 IP 在黑名单中就拦截,如果不在就返回 None (函数中没有返回值其实就是默认为 None),把这个中间件的 Python 路径写到settings.py中

1
2
3
4
MIDDLEWARE_CLASSES = (
'zqxt.middleware.BlockedIpMiddleware',
...其它的中间件
)

Django 会从 MIDDLEWARE_CLASSES 中按照从上到下的顺序一个个执行中间件中的 process_request 函数,而其中 process_response 函数则是最前面的最后执行。
2.再比如,我们在网站放到服务器上正式运行后,DEBUG改为了 False,这样更安全,但是有时候发生错误我们不能看到错误详情,调试不方便,有没有办法处理好这两个事情呢?
(1)普通访问者看到的是友好的报错信息。
(2)管理员看到的是错误详情,以便于修复BUG

1
2
3
4
5
6
7
8
import sys
from django.views.debug import technical_500_response
from django.conf import settings

class UserBasedExceptionMiddleware(object):
def process_exception(self, request, exception):
if request.user.is_superuser or request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
return technical_500_response(request, *sys.exc_info())

3、识别手机的中间件

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
MOBILE_USERAGENTS = ("2.0 MMP","240x320","400X240","AvantGo","BlackBerry",
"Blazer","Cellphone","Danger","DoCoMo","Elaine/3.0","EudoraWeb",
"Googlebot-Mobile","hiptop","IEMobile","KYOCERA/WX310K","LG/U990",
"MIDP-2.","MMEF20","MOT-V","NetFront","Newt","Nintendo Wii","Nitro",
"Nokia","Opera Mini","Palm","PlayStation Portable","portalmmm","Proxinet",
"ProxiNet","SHARP-TQ-GX10","SHG-i900","Small","SonyEricsson","Symbian OS",
"SymbianOS","TS21i-10","UP.Browser","UP.Link","webOS","Windows CE",
"WinWAP","YahooSeeker/M1A1-R2D2","iPhone","iPod","Android",
"BlackBerry9530","LG-TU915 Obigo","LGE VX","webOS","Nokia5800")

class MobileTemplate(object):
"""
If a mobile user agent is detected, inspect the default args for the view
func, and if a template name is found assume it is the template arg and
attempt to load a mobile template based on the original template name.
"""

def process_view(self, request, view_func, view_args, view_kwargs):
if any(ua for ua in MOBILE_USERAGENTS if ua in
request.META["HTTP_USER_AGENT"]):
template = view_kwargs.get("template")
if template is None:
for default in view_func.func_defaults:
if str(default).endswith(".html"):
template = default
if template is not None:
template = template.rsplit(".html", 1)[0] + ".mobile.html"
try:
get_template(template)
except TemplateDoesNotExist:
pass
else:
view_kwargs["template"] = template
return view_func(request, *view_args, **view_kwargs)
return None

热评文章