命令使用
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 | def add(request): |
url匹配参数与express不同
1 | def add2(request,a,b): |
巧妙访问网页
1 | 不带参数的: |
模板:模板中的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 empty1
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 | {% if request.user.is_authenticated %} |
数据库模型
1 | from django.db import models |
新建一个对象的方法有以下几种:
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 | #coding:utf-8 |
数据表修改
South工具
(1)QuerySet创建对象的方法
(2)获取对象的方法
(3)QuerySet是可迭代的
(4)QuerySet是可以用pickle序列化到硬盘再读取出来
(5)QuerySet查询结果排序
(6)QuerySet支持链式查询
(7)QuerySet不支持负索引
(8)QuerySet重复的问题,使用.distinct()去重
django后台
1 | # coding:utf-8 |
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
12from 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.py1
2
3
4
5from django import forms
class AddForm(forms.Form):
a = forms.IntegerField()
b = forms.IntegerField()
views.py1
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.html1
2
3
4
5<form method='post'>
{% csrf_token %}
{{ form }}
<input type="submit" value="提交">
</form>
urls.py1
2
3
4
5
6
7
8
9
10from 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 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) |
这里用到了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
2STATIC_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
4STATICFILES_DIRS = (
os.path.join(BASE_DIR, "common_static"),
'/var/www/static/',
)
这样我们就可以把静态文件放在 common_static 和 /var/www/static/中了,Django也能找到它们。1
2MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
media文件夹用来存放用户上传的文件,与权限有关,详情见 Django 静态文件 和 Django 部署1
2
3
4
5
6
7
8
9TEMPLATES = [
{
'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 | # Static files (CSS, JavaScript, Images) |
自己分配静态文件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 | from django.conf.urls.static import static |
django部署
apache部署和nginx部署
文本数据导入
1 | #!/usr/bin/env python |
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数据导入
mysql1
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.py1
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.py1
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
11python 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.py1
2
3
4
5{
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
}
}
利用文件系统来缓存1
2
3
4
5
6
7
8
9
10CACHES = {
'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
10CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'cache_table_name',
'TIMEOUT': 600,
'OPTIONS': {
'MAX_ENTRIES': 2000
}
}
}
django缓存系统实例1
2
3
4
5from django.shortcuts import render
def index(request):
# 读取数据库等 并渲染到网页
# 数据库获取的结果保存到 queryset 中
return render(request, 'index.html', {'queryset':queryset})
像这样每次访问都要读取数据库,一般的小网站没什么问题,当访问量非常大的时候,就会有很多次的数据库查询,肯定会造成访问速度变慢,服务器资源占用较多等问题。1
2
3
4
5
6
7from django.shortcuts import render
from django.views.decorators.cache import cache_page
def index(request):
# 读取数据库等 并渲染到网页
return render(request, 'index.html', {'queryset':queryset})
django生成静态网页
views.py1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from 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.py1
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
33MIDDLEWARE_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
2python 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',
在视图中使用session1
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
9from 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
15def 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.py1
2
3
4
5
6from __future__ import unicode_literals
from django.shortcuts import render
def home(request):
List = ['自强学堂', '渲染Json到模板']
return render(request, 'home.html', {'List': List})
home.html1
2
3
4<script type="text/javascript">
var List = {{ List }};
alert(List);
</script>
会报错
需要注意两点:
- views.py中返回的函数中的值要用 json.dumps()处理
- 在网页上要加一个 safe 过滤器。
views.py1
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
4MIDDLEWARE_CLASSES = (
'zqxt.middleware.BlockedIpMiddleware',
...其它的中间件
)
Django 会从 MIDDLEWARE_CLASSES 中按照从上到下的顺序一个个执行中间件中的 process_request 函数,而其中 process_response 函数则是最前面的最后执行。
2.再比如,我们在网站放到服务器上正式运行后,DEBUG改为了 False,这样更安全,但是有时候发生错误我们不能看到错误详情,调试不方便,有没有办法处理好这两个事情呢?
(1)普通访问者看到的是友好的报错信息。
(2)管理员看到的是错误详情,以便于修复BUG1
2
3
4
5
6
7
8import 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
35MOBILE_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