Django Web补充
一、今日内容
一、Django ORM连表操作
Q,F
二、Form表单验证
面向对象
正则
三、Session框架
面向对象
cookie
toanado扩展
二、Django ORM一对多数据创建和查找
1、数据创建
对于不是外键关联的表,可以直接创建
对于通过外键关联的表,可以通过两种方式创建数据:
方式a:通过id添加数据
def user_info(request): dic = {'username':'xx','age':88,'user_type_id':1} #通过id添加数据 models.UserInfo.objects.create(**dic) result = models.UserInfo.objects.all() for item in result: print item.username,item.age,item.user_type.caption #对象访问属性
方式b:
dic = {'username':'alex','age':73,'user_type':models.UserType.objects.get(id=1)} models.UserInfo.objects.create(**dic) result = models.UserInfo.objects.all() for item in result: print item.username,item.age,item.user_type.caption #对象访问属性
2、数据正向查找
对于不是外键关联的数据,直接通过如下方式查找
models.UserInfo.objects.filter(username='alex') #不是外键关联的数据
对于外键关联的数据,通过"__"双下划线如下的方式查找:
result = models.UserInfo.objects.filter(user_type__caption="CEO") #通过外键关联的数据的查找方式 for item in result: print item.username,item.age,item.user_type.caption return HttpResponse("OK")
3、数据反向查找
首先看一下表结构
from django.db import models class UserType(models.Model): caption = models.CharField(max_length=32) class UserInfo(models.Model): user_type = models.ForeignKey(UserType) #在创建数据的时候,需要下来创建选择用户类型,这种情况下需要是一对多 username = models.CharField(max_length=32) age = models.IntegerField()
可以看到UserType是通过外键被UserInfo表关联的表,所以,通过Usertype查找UserInfo表中的数据,称为反向查找
现在有如下需求:要求获取某个人的用户类型,并计算出该用户类型的用户的数量
分析:用户类型存在于UserType表中,但是用户名存在于UserInfo表中,可以直接通过正向查找,在Usertype表中获取指定用户的用户类型,因为用户名是跨表的,需要通过双下划线表示
通过在UserType表中创建用户类型的对象,利用_set反向关联UserInfo表,查找到对应用户的数量;
user_type_obj =models.UserType.objects.get(userinfo__username='alex') #对象(UserType) print user_type_obj.caption #实例 print user_type_obj.userinfo_set.all().count() return HttpResponse("OK")
在举一个栗子:
在前面的BBS项目中,如果要获取所有文章的点赞的个数,该如何实现呢?首先请看下面的表结构:
class MyUser(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) def __unicode__(self): return self.username class NEWs(models.Model): title = models.CharField(max_length=32) content = models.CharField(max_length=32) def __unicode__(self): return self.title class Favor(models.Model): user_obj = models.ForeignKey(MyUser) new_obj = models.ForeignKey(NEWs) def __unicode__(self): return "%s --> %s" %(self.user_obj.username,self.new_obj.title)
从上面的表结构可以看出,点赞的表Favor通过外键关联NEWs表和MyUser表,通过NEWs表,获取Favor表中的数据的个数,需要通过反向查找获取,如下:
new_list = models.NEWs.objects.all() #获取文章的实例 for item in new_list: print item.title print "#############" print item.content print item.favor_set.all().count() #反向查找
接下来需求改变,要求查找dali赞过的文章的个数;
分析:如果从NEWs表中开始查找,创建对象的时候需要通过双下划线跨表查询NEWs-->Favor-->MyUser,直到找到条件username=dali为止;
new_list = models.NEWs.objects.filter(favor__user_obj__username='dali') #filter返回的是列表,没有返回为[]
for item in new_list: print item.title print "#############" print item.content print item.favor_set.all().count()
注意:在创建对象的时候,如果是条件查询,需要使用到filter和get,注意区别是:get返回的是字典,无需循环,通过.直接获取需要的字段,并且如果返回值的不唯一或为空,就会报错;而对于filter返回的则是列表,返回值不唯一不会报错,并且如果值为空,返回[],注意获取字段的时候,需要循环; all()返回的也是列表;
4、好了,现在将数据查找的两种方式总结如下:
正向查找: filter(跨表) 对象__跨表的字段
line.对象.跨表的字段
反向查找:filter(跨表) 自动创建一个与表名相同的对象__跨表的字段
line.自动创建一个与表名相同的对象__set.filter()/all()[0:1]
二、Django ORM多对多数据创建和查找
1、正向添加数据
首先看一下表结构,对于多对多来讲,外键关联的字段HostAdmin/host可以放在任何一张表中,只不过这时候需要注意正向和反向即可
class Host(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField() class HostAdmin(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) host=models.ManyToManyField(Host)
接下来创建数据
models.Host.objects.create(hostname='c1',port=80) models.Host.objects.create(hostname='c2',port=80) models.Host.objects.create(hostname='c3',port=80) models.HostAdmin.objects.create(username='alex',email='1@live.com') models.HostAdmin.objects.create(username='root',email='2@live.com') models.HostAdmin.objects.create(username='dali',email='3@live.com') models.HostAdmin.objects.create(username='haojie',email='4@live.com')
数据内容如下所示:
现在需要在关联的表host表中创建数据如下:
正向创建数据
admin_obj=models.HostAdmin.objects.get(username='dali') #创建username的对象 host_list=models.Host.objects.filter(id__lt=3) #创建主机id小于3的对象 admin_obj.host.add(*host_list) #添加数据 return HttpResponse("OK")
2、反向数据添加
host_obj =models.Host.objects.get(id=3) admin_list = models.HostAdmin.objects.filter(id__gt=1) #id值大于1 host_obj.hostadmin_set.add(*admin_list) #反向数据添加
总结:正向数据添加还是反向数据添加,取决于多对多的关联的字段存在于哪个表中;相同点是:都是一张表中的一个固定的值对另外一张表的多个值;
3、Django 多对多自定义第三张关系表
如下三张表,对于第三张关系表,第一张表和第二张表是第三张表的外键,其表中的字段全部通过外键关联其他的表,那么可不可以让第三张表中存在其他的字段呢?答案是可以的
看下面:Django 多对多ORM创建第三张自定义的关系表,通过through参数实现;
class Host1(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField() class HostAdmin1(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) host=models.ManyToManyField(Host1,through='HostRelation') class HostRelation(models.Model): c1=models.ForeignKey(Host1) C2=models.ForeignKey(HostAdmin1)
#可以在下面继续增加其他的字段,如果需要的话
那问题来了?自定义的第三张表有了,数据如何写入呢?
事实上,此时在第三张表中写入数据,是写入的id的值,有两种方式:通过查询对象写入和直接写入,看下面
#通过查询对象写入,需要查询之后执行数据库操作
models.HostRelation.objects.create( c1=models.Host1.objects.get(id=1), C2=models.HostAdmin1.objects.get(id=2) )
#直接写入,无需查询,推荐的方式;
models.HostRelation.objects.create( #0次数据库查询,一次数据库插入 c1_id=2, C2_id=1, )
4、Django ORM多对多数据查询的两种方式
方式1:
#正向查 admin_obj =models.HostAdmin.objects.get(id=1) admin_obj.host.all() #反向查 host_obj =models.Host.objects.get(id=1) host_obj.hostadmin_set.all()
方式2:通过自定义的第三张表查询(推荐)
relation_list = models.HostRelation.objects.all() for item in relation_list: print item.c1.hostname print item.C2.username relation_list1 = models.HostRelation.objects.filter(C2__username='alex') for item in relation_list1: print item.c1.hostname print item.C2.username
比较:第二种方式可以查询所有的数据,并且操作数据库的次数少,,并且便于扩展(添加新的字段)推荐使用;
5、ORM查询使用select_related()
ret = models.UserInfo.objects.all()
print ret.query
SQL为:
SELECT "app01_userinfo"."id",
"app01_userinfo"."user_type_id",
"app01_userinfo"."username",
"app01_userinfo"."age"
FROM "app01_userinfo"
ret = models.UserInfo.objects.all().select_related()
print ret.query SQL为: SELECT "app01_userinfo"."id", "app01_userinfo"."user_type_id", "app01_userinfo"."username", "app01_userinfo"."age", "app01_usertype"."id", "app01_usertype"."caption" FROM "app01_userinfo" INNER JOIN "app01_usertype" ON ( "app01_userinfo"."user_type_id" = "app01_usertype"."id" )
select_related()会将外键关联的表进行关联查询,会将全部Foreignkey加载到内存;
6、ORM之F和ORM之Q
需求:将数据库中age字段的值都加以 model.tb.object.all().update(age=F('age')+1) #F表示当前行的数据
一般对于使用ORM filter查询数据的时候,只能添加一个条件,那么如果需要添加多个条件呢?
ORM Q可以创建多个条件供filter查询
现在要求查询:主机名为c1或c2或c3或c4并且状态都为在线的主机 from django.db.models import Q con=Q() 主机名:c1,c2,c3,c4 ===> q1 =Q() q1=Q() q1.connector="OR" q1.children.append(('hostname',"c1")) #此处的主机名可以使用双下划线进行跨表关联 q1.children.append(('hostname',"c2")) q1.children.append(('hostname',"c3")) q1.children.append(('hostname',"c4")) 状态:上线,上架 ===>q2 ==Q() q2=Q() q2.connector="OR" q2.children.append(('status',"online")) q2.children.append(('status',"online2")) con.add((q1,'ADD')) con.add((q2,'ADD')) models.TB1.objects.filter(con)
就是将q1和q2两个条件一起放到con条件下面,产生多个条件;
#!/usr/bin/env python # -*- coding:utf-8 -*- import json from backend.response.base_response import BaseResponse from django.db import transaction from web_manage.dal import asset from web_manage.dal import user_profile from web_manage.dal import contract from web_manage.dal import idc from web_manage.dal import server from web_manage.dal import device_status from web_manage.dal import business_unit from web_manage.dal import device_type from web_manage.dal import nic from web_manage.dal import memory from web_manage.dal import disk from web_manage.dal import handle_log from django.db.models import Q def asset_import_single(**kwargs): response = BaseResponse() try: with transaction.atomic(): manage_ip = kwargs.pop('manage_ip') hostname = kwargs.pop('hostname') sn = kwargs.pop('sn') kwargs['idc'] = idc.get_obj_by_id(kwargs['idc']) kwargs['contract'] = contract.get_obj_by_id(kwargs['contract']) #kwargs['manage_user'] = user_profile.get_obj_by_id(kwargs['manage_user']) kwargs['device_status'] = device_status.get_obj_by_code('1000') kwargs['device_type'] = device_type.get_obj_by_code('1000') kwargs['business_unit'] = business_unit.get_obj_by_id(kwargs['business_unit']) asset_obj = asset.add(**kwargs) server.add(asset=asset_obj, manage_ip=manage_ip, hostname=hostname, sn=sn) response.data = asset_obj response.status = True except Exception, e: response.message = e return response def get_asset_lists_count(conditions): response = BaseResponse() try: # base ip get server object ip ips = conditions.get('ips__contains', None) if not ips: pass else: del conditions['ips__contains'] q_ip = Q() q_ip.connector = 'OR' server_ids = [] for item in (ips if ips else []): q_ip.children.append(("ipaddrs__contains", item)) server_ips = nic.get_field_by_q_group(q_ip, 'server_info', *['server_info__id']) for item in server_ips: if item: server_ids.append(item.values()[0]) if server_ids: conditions['server__id'] = server_ids else: conditions['server__id'] = [0, ] # create search condition con = Q() for k, v in conditions.items(): temp = Q() temp.connector = 'OR' for item in v: temp.children.append((k, item)) con.add(temp, 'AND') # do search result = asset.get_asset_lists_q_count(con) response.data = result response.status = True except Exception,e: response.message = str(e) return response def get_asset_lists(conditions, start, end): response = BaseResponse() try: values = ['id', 'cabinet_num', 'cabinet_order', 'server__manage_ip', 'server', 'server__hostname', 'server__sn', 'device_type__id', 'device_type__name', 'device_status__id', 'device_status__name', 'business_unit__id', 'business_unit__name', 'idc__id', 'idc__display', 'contract__id', 'contract__name'] # base ip get server object ip ips = conditions.get('ips__contains', None) if not ips: pass else: del conditions['ips__contains'] q_ip = Q() q_ip.connector = 'OR' server_ids = [] for item in (ips if ips else []): q_ip.children.append(("ipaddrs__contains", item)) server_ips = nic.get_field_by_q_group(q_ip, 'server_info', *['server_info__id']) for item in server_ips: if item: server_ids.append(item.values()[0]) if server_ids: conditions['server__id'] = server_ids else: conditions['server__id'] = [0, ] # create search condition con = Q() for k, v in conditions.items(): temp = Q() temp.connector = 'OR' for item in v: temp.children.append((k, item)) con.add(temp, 'AND') # do search result = asset.get_asset_lists_q(start, end, con, *values) # get ip info for item in result: ips = nic.get_field_by_server(item['server'], *['ipaddrs', ]) item['ips'] = list(ips) result = list(result) response.data = result response.status = True except Exception,e: response.message = str(e) return response def __asset_update_log(row, user): with transaction.atomic(): asset_obj = asset.get_asset_by_id(row['id']) server_obj = server.get_obj_by_asset(asset_obj) log_list = [] if(row.has_key('cabinet_order')): log_list.append(u"机柜由【%s】变更为【%s】" % (asset_obj.cabinet_order, row['cabinet_order'])) asset_obj.cabinet_order = row['cabinet_order'] if(row.has_key('cabinet_num')): log_list.append(u"柜上位置由【%s】变更为【%s】" % (asset_obj.cabinet_num, row['cabinet_num'])) asset_obj.cabinet_num = row['cabinet_num'] if(row.has_key('contract')): log_list.append(u"合同由【%s】变更为【%s】" % (asset_obj.contract.name, row['contract'])) asset_obj.contract = contract.get_obj_by_name(row['contract']) if(row.has_key('business_unit')): log_list.append(u"业务线由【%s】变更为【%s】" % (asset_obj.business_unit.name, row['business_unit'])) asset_obj.business_unit = business_unit.get_obj_by_name(row['business_unit']) if(row.has_key('idc')): log_list.append(u"IDC由【%s】变更为【%s】" % (asset_obj.idc.display, row['idc'])) asset_obj.idc = idc.get_obj_by_display(row['idc']) if(row.has_key('device_status')): log_list.append(u"设备状态由【%s】变更为【%s】" % (asset_obj.device_status.name, row['device_status'])) asset_obj.device_status = device_status.get_obj_by_name(row['device_status']) if(row.has_key('manage_ip')): log_list.append(u"管理IP由【%s】变更为【%s】" %(server_obj.manage_ip, row['manage_ip'])) server_obj.manage_ip = row['manage_ip'] if(row.has_key('hostname')): log_list.append(u"主机名由【%s】变更为【%s】" %(server_obj.hostname, row['hostname'])) server_obj.hostname = row['hostname'] if(row.has_key('sn')): log_list.append(u"SN号由【%s】变更为【%s】" %(server_obj.sn, row['sn'])) server_obj.sn = row['sn'] server_obj.save() asset_obj.save() if log_list: handle_log.write_handle_log(asset_obj, user, ';'.join(log_list)) def del_asset(rows): response = BaseResponse() error_count = 0 error_message = [] try: rows = json.loads(rows) except Exception, e: response.status = 0 response.data = str(e) response.message = error_message return response for row in rows: try: with transaction.atomic(): asset_obj = asset.get_asset_by_id(row['nid']) server_obj = asset_obj.server nic.del_by_server(server_obj) disk.del_by_server(server_obj) memory.del_by_server(server_obj) handle_log.del_by_asset(asset_obj) server_obj.delete() asset_obj.delete() except Exception, e: error_count += 1 error_message.append({'num': row['num'], 'message': str(e)}) if error_count == 0: response.status = 1 response.data = "删除%d条,成功%d." % (len(rows), len(rows)-error_count) elif error_count > 0: response.status = 0 response.data = "删除%d条,成功%d,失败%d." % (len(rows), len(rows)-error_count, error_count) response.message = error_message return response def modify_multi_asset(data, user): # 临时 response = BaseResponse() rows = json.loads(data) error_count = 0 error_message = [] user = json.loads(user) current_user_id = user['id'] current_user_obj = user_profile.get_obj_by_id(current_user_id) for item in rows: try: __asset_update_log(item, current_user_obj) except Exception, e: error_count += 1 error_message.append({'num': item['num'], 'message': str(e)}) if error_count == 0: response.status = 1 response.data = "更新%d条,成功%d." % (len(rows), len(rows)-error_count) elif error_count > 0: response.status = 0 response.data = "更新%d条,成功%d,失败%d." % (len(rows), len(rows)-error_count, error_count) response.message = error_message print response return response def get_asset_detail(nid): response = BaseResponse() try: asset_obj = asset.get_asset_by_id(nid) nic_list = nic.get_objs_by_server(asset_obj.server) mem_list = memory.get_objs_by_server(asset_obj.server) disk_list = disk.get_objs_by_server(asset_obj.server) log_list = handle_log.get_handle_log(asset_obj=asset_obj) result = {'asset': asset_obj, 'nic': nic_list, 'memory': mem_list, 'disk': disk_list, 'log': log_list} response.status = True response.data = result except Exception, e: response.message = str(e) return response def init_config(nid): response = BaseResponse() try: asset_obj = asset.get_asset_by_id(nid) result = asset.get_init(asset_obj.server.manage_ip) asset_obj.server.service_sn = result['service_sn'] asset_obj.server.sn = result['sn'] asset_obj.server.first_mac = result['first_mac'] asset_obj.server.save() response.status = True response.data = '初始化成功.' except Exception, e: response.status = False response.message = str(e) return response # ########################## 获取字典表 ########################## # def get_all_idc(): response = BaseResponse() try: values = ['id','display'] result = idc.get_all(*values) result = list(result) response.data = result response.status = True except Exception,e: response.message = str(e) return response def get_all_status(): response = BaseResponse() try: values = ['id', 'name', ] result = device_status.get_all(*values) result = list(result) response.data = result response.status = True except Exception,e: response.message = str(e) return response def get_all_user_basic_op(): response = BaseResponse() try: values = ['id', 'name', ] result = user_profile.get_all_basic_op(*values) result = list(result) response.data = result response.status = True except Exception,e: response.message = str(e) return response def get_all_business_unit(): response = BaseResponse() try: values = ['id', 'name', ] result = business_unit.get_all(*values) result = list(result) response.data = result response.status = True except Exception,e: response.message = str(e) return response def get_all_contract(): response = BaseResponse() try: values = ['id', 'name', ] result = contract.get_all(*values) result = list(result) response.data = result response.status = True except Exception,e: response.message = str(e) return response
7、作业:搜索功能开发
那么作业来了: 前端输入多个用户、多个年龄或者用户类型来搜索用户 姓名:<input name="username" /> 年龄:<input name="age" /> 用户类型:<input name="user_type__caption" /> #跨表 AJAX { "username":[c1,c2,c3], "age":[18,19] } 后台 dic 在前端获取 con = Q() for key,value in dic: q=Q() q.connettor="OR" for v in value: q.children.append((key,v)) con.add(q,'ADD') model.Tb1.objects.filter(con)