7、Model连表操作
- 指定映射
- 连表条件
- 一对一
- 多对多
class UserProfile(models.Model):
user_info = models.OneToOneField(‘UserInfo‘)
username = models.CharField(max_length=64)
password = models.CharField(max_length=64)
def __unicode__(self):
return self.username
class UserInfo(models.Model):
user_type_choice = (
(0, u‘普通用户‘),
(1, u‘高级用户‘),
)
user_type = models.IntegerField(choices=user_type_choice)
name = models.CharField(max_length=32)
email = models.CharField(max_length=32)
address = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class UserGroup(models.Model):
caption = models.CharField(max_length=64)
user_info = models.ManyToManyField(‘UserInfo‘)
def __unicode__(self):
return self.caption
class Host(models.Model):
hostname = models.CharField(max_length=64)
ip = models.GenericIPAddressField()
user_group = models.ForeignKey(‘UserGroup‘)
def __unicode__(self):
return self.hostname
表结构
一对一
1
2
3
4
5
6
7
8
|
user_info_obj = models.UserInfo.objects. filter ( id = 1 ).first()
print user_info_obj.user_type
print user_info_obj.get_user_type_display()
print user_info_obj.userprofile.password
user_info_obj = models.UserInfo.objects. filter ( id = 1 ).values( ‘email‘ , ‘userprofile__username‘ ).first()
print user_info_obj.keys()
print user_info_obj.values()
|
多对多表之间的查询
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
|
user_info_obj = models.UserInfo.objects.get(name = u ‘武沛齐‘ )
user_info_objs = models.UserInfo.objects. all ()
group_obj = models.UserGroup.objects.get(caption = ‘CEO‘ )
group_objs = models.UserGroup.objects. all ()
# 添加数据
#group_obj.user_info.add(user_info_obj)
#group_obj.user_info.add(*user_info_objs)
# 删除数据
#group_obj.user_info.remove(user_info_obj)
#group_obj.user_info.remove(*user_info_objs)
# 添加数据
#user_info_obj.usergroup_set.add(group_obj)
#user_info_obj.usergroup_set.add(*group_objs)
# 删除数据
#user_info_obj.usergroup_set.remove(group_obj)
#user_info_obj.usergroup_set.remove(*group_objs)
# 获取数据
#print group_obj.user_info.all()
#print group_obj.user_info.all().filter(id=1)
# 获取数据
#print user_info_obj.usergroup_set.all()
#print user_info_obj.usergroup_set.all().filter(caption=‘CEO‘)
#print user_info_obj.usergroup_set.all().filter(caption=‘DBA‘)
|
注意:xx_set中的【_set】是固定搭配
8、Form
django中的Form一般有两种功能:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError
def mobile_validate(value):
mobile_re = re.compile(r‘^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$‘)
if not mobile_re.match(value):
raise ValidationError(‘手机号码格式错误‘)
class PublishForm(forms.Form):
user_type_choice = (
(0, u‘普通用户‘),
(1, u‘高级用户‘),
)
user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
attrs={‘class‘: "form-control"}))
title = forms.CharField(max_length=20,
min_length=5,
error_messages={‘required‘: u‘标题不能为空‘,
‘min_length‘: u‘标题最少为5个字符‘,
‘max_length‘: u‘标题最多为20个字符‘},
widget=forms.TextInput(attrs={‘class‘: "form-control",
‘placeholder‘: u‘标题5-20个字符‘}))
memo = forms.CharField(required=False,
max_length=256,
widget=forms.widgets.Textarea(attrs={‘class‘: "form-control no-radius", ‘placeholder‘: u‘详细描述‘, ‘rows‘: 3}))
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={‘required‘: u‘手机不能为空‘},
widget=forms.TextInput(attrs={‘class‘: "form-control",
‘placeholder‘: u‘手机号码‘}))
email = forms.EmailField(required=False,
error_messages={‘required‘: u‘邮箱不能为空‘,‘invalid‘: u‘邮箱格式错误‘},
widget=forms.TextInput(attrs={‘class‘: "form-control", ‘placeholder‘: u‘邮箱‘}))
Form
Form
def publish(request):
ret = {‘status‘: False, ‘data‘: ‘‘, ‘error‘: ‘‘, ‘summary‘: ‘‘}
if request.method == ‘POST‘:
request_form = PublishForm(request.POST)
if request_form.is_valid():
request_dict = request_form.clean()
print request_dict
ret[‘status‘] = True
else:
error_msg = request_form.errors.as_json()
ret[‘error‘] = json.loads(error_msg)
return HttpResponse(json.dumps(ret))
views
扩展:ModelForm
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义
1
2
3
4
5
6
7
8
9
10
|
class AdminModelForm(forms.ModelForm):
class Meta:
model = models.Admin
#fields = ‘__all__‘
fields = ( ‘username‘ , ‘email‘ )
widgets = {
‘email‘ : forms.PasswordInput(attrs = { ‘class‘ : "alex" }),
}
|
9、分页
分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...)
3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
4、在数据表中根据起始位置取值,页面上输出数据
需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]
1、设定每页显示数据条数
2、用户输入页码(第一页、第二页...)
3、设定显示多少页号
4、获取当前数据总条数
5、根据设定显示多少页号和数据总条数计算出,总页数
6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置
7、在数据表中根据起始位置取值,页面上输出数据
8、输出分页html,如:[上一页][1][2][3][4][5][下一页]
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
66
67
68
69
70
71
72
73
|
#!/usr/bin/env python
# _*_coding:utf-8_*_
from django.utils.safestring import mark_safe
class PageInfo( object ):
def __init__( self ,current,totalItem,peritems = 5 ):
self .__current = current
self .__peritems = peritems
self .__totalItem = totalItem
def From( self ):
return ( self .__current - 1 ) * self .__peritems
def To( self ):
return self .__current * self .__peritems
def TotalPage( self ): #总页数
result = divmod ( self .__totalItem, self .__peritems)
if result[ 1 ] = = 0 :
return result[ 0 ]
else :
return result[ 0 ] + 1
def Custompager(baseurl,currentPage,totalpage): #基础页,当前页,总页数
perPager = 11
#总页数<11
#0 -- totalpage
#总页数>11
#当前页大于5 currentPage-5 -- currentPage+5
#currentPage+5是否超过总页数,超过总页数,end就是总页数
#当前页小于5 0 -- 11
begin = 0
end = 0
if totalpage < = 11 :
begin = 0
end = totalpage
else :
if currentPage> 5 :
begin = currentPage - 5
end = currentPage + 5
if end > totalpage:
end = totalpage
else :
begin = 0
end = 11
pager_list = []
if currentPage< = 1 :
first = "<a href=‘‘>首页</a>"
else :
first = "<a href=‘%s%d‘>首页</a>" % (baseurl, 1 )
pager_list.append(first)
if currentPage< = 1 :
prev = "<a href=‘‘>上一页</a>"
else :
prev = "<a href=‘%s%d‘>上一页</a>" % (baseurl,currentPage - 1 )
pager_list.append(prev)
for i in range (begin + 1 ,end + 1 ):
if i = = currentPage:
temp = "<a href=‘%s%d‘ class=‘selected‘>%d</a>" % (baseurl,i,i)
else :
temp = "<a href=‘%s%d‘>%d</a>" % (baseurl,i,i)
pager_list.append(temp)
if currentPage> = totalpage:
next = "<a href=‘#‘>下一页</a>"
else :
next = "<a href=‘%s%d‘>下一页</a>" % (baseurl,currentPage + 1 )
pager_list.append( next )
if currentPage> = totalpage:
last = "<a href=‘‘>末页</a>"
else :
last = "<a href=‘%s%d‘>末页</a>" % (baseurl,totalpage)
pager_list.append(last)
result = ‘‘.join(pager_list)
return mark_safe(result) #把字符串转成html语言
|
总结,分页时需要做三件事:
- 创建处理分页数据的类
- 根据分页数据获取数据
- 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]
10、Cookie和Session
操作Cookie
获取cookie:request.COOKIES[key]
设置cookie:response.set_cookie(key,value)
由于cookie保存在客户端的电脑上,所以,jquery也可以操作cookie。
1
2
|
<script src = ‘/static/js/jquery.cookie.js‘ >< / script>
$.cookie( "list_pager_num" , 30 ,{ path: ‘/‘ });
|
操作Session
获取session:request.session[key]
设置session:reqeust.session[key] = value
删除session:del request[key]
1
2
3
4
5
|
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是 0 ,用户关闭浏览器session就会失效。
* 如果value是 None ,session会依赖全局session失效策略。
|
更多见:http://docs.30c.org/djangobook2/chapter14/
应用
1
2
3
4
5
6
7
|
def login(func):
def wrap(request, * args, * * kwargs):
# 如果未登陆,跳转到指定页面
if request.path = = ‘/test/‘ :
return redirect( ‘http://www.baidu.com‘ )
return func(request, * args, * * kwargs)
return wrap
|
11、Ajax
1
2
3
4
5
6
7
8
9
10
11
|
$.ajax({
url: "/web/index/" ,
data:{ id : 1 ,name: ‘alex‘ },
type : ‘POST‘ ,
success:function(data){
},
error:function(){
}
});
|
12、跨站请求伪造
简介
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
应用
1、普通表单
1
2
3
4
5
|
veiw中设置返回值:
return render_to_response( ‘Account/Login.html‘ ,data,context_instance = RequestContext(request))
html中设置Token:
{ % csrf_token % }
|
2、Ajax
对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。
view.py
1
2
3
4
5
6
7
8
9
10
|
from django.template.context import RequestContext
# Create your views here.
def test(request):
if request.method = = ‘POST‘ :
print request.POST
return HttpResponse( ‘ok‘ )
return render_to_response( ‘app01/test.html‘ ,context_instance = RequestContext(request))
|
text.html
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
|
<!DOCTYPE html>
<html>
<head lang = "en" >
<meta charset = "UTF-8" >
<title>< / title>
< / head>
<body>
{ % csrf_token % }
< input type = "button" onclick = "Do();" value = "Do it" / >
<script src = "/static/plugin/jquery/jquery-1.8.0.js" >< / script>
<script src = "/static/plugin/jquery/jquery.cookie.js" >< / script>
<script type = "text/javascript" >
var csrftoken = $.cookie( ‘csrftoken‘ );
function csrfSafeMethod(method) {
/ / these HTTP methods do not require CSRF protection
return ( / ^(GET|HEAD|OPTIONS|TRACE)$ / .test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings. type ) && !this.crossDomain) {
xhr.setRequestHeader( "X-CSRFToken" , csrftoken);
}
}
});
function Do(){
$.ajax({
url: "/app01/test/" ,
data:{ id : 1 },
type : ‘POST‘ ,
success:function(data){
console.log(data);
}
});
}
< / script>
< / body>
< / html>
|
更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
13、中间件
简介
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。
与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类
中间件中可以定义四个方法,分别是:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_exception(self, request, exception)
- process_response(self, request, response)
以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。
自定义中间件
1、创建中间件类
1
2
3
4
5
6
7
8
9
10
11
12
|
class RequestExeute( object ):
def process_request( self ,request):
pass
def process_view( self , request, callback, callback_args, callback_kwargs):
i = 1
pass
def process_exception( self , request, exception):
pass
def process_response( self , request, response):
return response
|
2、注册中间件
1
2
3
4
5
6
7
8
9
10
|
MIDDLEWARE_CLASSES = (
‘django.contrib.sessions.middleware.SessionMiddleware‘ ,
‘django.middleware.common.CommonMiddleware‘ ,
‘django.middleware.csrf.CsrfViewMiddleware‘ ,
‘django.contrib.auth.middleware.AuthenticationMiddleware‘ ,
‘django.contrib.auth.middleware.SessionAuthenticationMiddleware‘ ,
‘django.contrib.messages.middleware.MessageMiddleware‘ ,
‘django.middleware.clickjacking.XFrameOptionsMiddleware‘ ,
‘wupeiqi.middleware.auth.RequestExeute‘ ,
)
|
14、admin
django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:
- 创建后台管理员
- 配置url
- 注册和配置django admin后台管理页面
1、创建后台管理员
1
|
python manage.py createsuperuser
|
2、配置后台管理url
1
|
url(r ‘^admin/‘ , include(admin.site.urls))
|
3、注册和配置django admin 后台管理页面
a、在admin中执行如下配置
1
2
3
4
5
6
7
8
|
from django.contrib import admin
from app01 import models
admin.site.register(models.UserType)
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
|
b、设置数据表名称
1
2
3
4
5
6
|
class UserType(models.Model):
name = models.CharField(max_length = 50 )
class Meta:
verbose_name = ‘用户类型‘
verbose_name_plural = ‘用户类型‘
|
c、打开表之后,设定默认显示,需要在model中作如下配置
1
2
3
4
5
|
class UserType(models.Model):
name = models.CharField(max_length = 50 )
def __unicode__( self ):
return self .name
|
+
d、为数据表添加搜索功能
1
2
3
4
5
6
7
8
9
10
11
12
|
from django.contrib import admin
from app01 import models
class UserInfoAdmin(admin.ModelAdmin):
list_display = ( ‘username‘ , ‘password‘ , ‘email‘ )
search_fields = ( ‘username‘ , ‘email‘ )
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
|
e、添加快速过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from django.contrib import admin
from app01 import models
class UserInfoAdmin(admin.ModelAdmin):
list_display = ( ‘username‘ , ‘password‘ , ‘email‘ )
search_fields = ( ‘username‘ , ‘email‘ )
list_filter = ( ‘username‘ , ‘email‘ )
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
|
更多:http://docs.30c.org/djangobook2/chapter06/
完善主机管理系统:
- 登陆注册(利用ajax实现,使用onblur事件,检测当前用户名是否已经存在)
- 用户会话保持(Session)
- Form验证用户输入
- 自定义中间件记录请求IP(或黑名单)
- 用户管理、用户组管理、主机管理(增删改查,分页)
- 自定义页面表格行数(可选)
时间: 2024-10-12 16:46:13