阿里山QQ

导航

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
View Code

 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)

 

posted on 2016-08-08 00:15  阿里山QQ  阅读(212)  评论(0编辑  收藏  举报