Django基础--3

ORM

django一对多的操作

获取表单的三种方式:views

获取对象            .all()      html中获取方式为 row.id,row,host

获取字典            .all().values("字段","字段","字段",……)  row.id,row,host

获取元祖            .all().values_list("字段","字段","字段",……) row.0,row.1

#views

from django.shortcuts import render
from app import models
# Create your views here.
def home(request):
    v1 = models.Host.objects.all()
    print(v1)
    #<QuerySet [<Host: Host object (1)>, <Host: Host object (2)>, <Host: Host object (3)>]> 对象
    v2 = models.Host.objects.all().values("host","port")
    print(v2)
    #< QuerySet[{'host': 'a', 'port': 80}, {'host': 'b', 'port': 81}, {'host': 'c', 'port': 82}] >  字典类型
    v3 = models.Host.objects.all().values_list("host","port")
    print(v3)
    #<QuerySet [('a', 80), ('b', 81), ('c', 82)]>  元祖类型
    retur

#html中

<body>
    <h1>主机信息</h1>
    <ul>
        {% for row in v1 %}
            <li>{{ row.id }}--- {{ row.host }}--- {{ row.ip }}--- {{ row.port }}--- {{ row.dept_id }}</li>
        {% endfor %}
    </ul>

    <h1>主机信息</h1>
    <ul>
        {% for row in v2 %}
            <li>{{ row.host }}--- {{ row.port }}</li>
        {% endfor %}
    </ul>

    <h1>主机信息</h1>
    <ul>
        {% for row in v3 %}
            <li>{{ row.0 }}--- {{ row.1 }}</li>
        {% endfor %}
    </ul>
</body>
View Code

一对多的跨表操作

获取对象 filter(id__gte=1)

#views

def host(request):
    v1 = models.Host.objects.filter(id__gte=1)
    return render(request,"host.html",{"v1":v1})


#urls.py


from app import views
path('host/', views.host),




#host.html
<body>
    <table border="1">
        <thead>
            <tr>
                <th>id</th>
                <th>主机名</th>
                <th>主机ip</th>
                <th>主机端口</th>
                <th>业务线</th>
                <th>部门</th>
                <th>部门代码</th>
            </tr>
        </thead>
        <tbody>
            {% for row in v1 %}
                <tr>
                    <td>{{ row.id }}</td>
                    <td>{{ row.host }}</td>
                    <td>{{ row.ip }}</td>
                    <td>{{ row.port }}</td>
                    <td>{{ row.dept_id }}</td>
                    <td>{{ row.dept.dept }}</td>
                    <td>{{ row.dept.dept_en }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
View Code

以上将所有的数据都显示出来了,然而实际中并用不到这么多,这里可以隐藏两个表的id,因每次都会循环tr,直接在<tr>中定义两个属性放id

这里修改下tbody里面内容即可

<tbody>
            {% for row in v1 %}
                <tr hid = "{{ row.id }}" bid = "{{ row.dept.id }}">
                    <td>{{ row.host }}</td>
                    <td>{{ row.ip }}</td>
                    <td>{{ row.port }}</td>
                    <td>{{ row.dept.dept }}</td>
                </tr>
            {% endfor %}
        </tbody>

获取字典 filter(id__gte=1).values("id","ip", "port", "dept_id","dept__dept")

#views.py

#获取类型为字典
    v2 = models.Host.objects.filter(id__gte=1).values("id","ip", "port", "dept_id","dept__dept")
    #print(v2)
    # <QuerySet [{'ip': '1.1.1.1', 'host': 'a', 'dept__dept': '运维'}, {'ip': '1.1.1.2', 'host': 'b', 'dept__dept': '销售'}, {'ip': '1.1.1.3', 'host': 'c', 'dept__dept': '信息部'}]>
    for i in v2:
        print(i["id"],i["ip"],i["port"],i["dept__dept"])
  return render(request,"host.html",{"v2":v2})

 

前端操作:

<h2>业务线-字典</h2>
    <table border="1">
        <thead>
            <tr>
                <th>主机ip</th>
                <th>主机端口</th>
                <th>部门</th>
            </tr>
        </thead>
        <tbody>
            {% for row in v2 %}
                <tr hid = "{{ row.id }}" bid = "{{ row.dept_id }}">
                    <td>{{ row.ip }}</td>
                    <td>{{ row.port }}</td>
                    <td>{{ row.dept__dept }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>

获取元祖  filter(id__gte=1).values_list("id","ip", "port", "dept_id","dept__dept")

v3 =  models.Host.objects.filter(id__gte=1).values_list("id","ip", "port", "dept_id","dept__dept")
    for j in v3:
        print(j[0],j[1],j[2],j[3],j[4],)
    return render(request,"host.html",{"v3":v3})

 

<h2>业务线-元祖</h2>
    <table border="1">
        <thead>
            <tr>
                <th>主机ip</th>
                <th>主机端口</th>
                <th>部门</th>
            </tr>
        </thead>
        <tbody>
            {% for row in v3 %}
                <tr hid = "{{ row.0 }}" bid = "{{ row.3 }}">
                    <td>{{ row.1 }}</td>
                    <td>{{ row.2 }}</td>
                    <td>{{ row.4}}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>

 总结

获取数据的3种方法中的第一种,页面中获取到的元素直接是对象,对对象用点就可以进行跨表
另外的两种方法,获取到的不再是对象了,而是字典和元组。这时候取值要传字符串,要跨表就得在字符串中使用双下划线

显示序号-for循环中的forloop

在模板语言的for循环里还有一个forloop,通过这个可以取到到序号:

  • forloop.counter :序号,从1开始
  • forloop.counter0 :序号,从0开始
  • forloop.revcounter :序号,倒序,从1开始
  • forloop.revcounter0 :序号,倒序,从0开始
  • forloop.first :是否是第一个
  • forloop.last :是否是最后一个
  • forloop.parentloop :有嵌套循环的情况下,获取父类的以上6个值。字典的形式,可以继续通过点来取到具体的值
<h2>forloop</h2>
    <table border="1">
        <thead>
            <tr>
                <th>forloop.counter </th>
                <th>forloop.counter0</th>
                <th>forloop.revcounter</th>
                <th>forloop.revcounter0</th>
                <th>forloop.first</th>
                <th>forloop.last</th>
                <th>forloop.parentloop</th>
                <th>主机ip</th>
                <th>主机端口</th>
                <th>部门</th>
            </tr>
        </thead>
        <tbody>
            {% for i in v3 %}
                {% for row in v3 %}
                    <tr hid = "{{ row.0 }}" bid = "{{ row.3 }}">
                        <td>{{ forloop.counter }}</td>
                        <td>{{ forloop.counter0 }}</td>
                        <td>{{ forloop.revcounter }}</td>
                        <td>{{ forloop.revcounter0 }}</td>
                        <td>{{ forloop.first}}</td>
                        <td>{{ forloop.last}}</td>
                        <td>{{ forloop.parentloop}}</td>
                        <td>{{ row.1 }}</td>
                        <td>{{ row.2 }}</td>
                        <td>{{ row.4}}</td>
                    </tr>
                {% endfor %}
            {% endfor %}
        </tbody>
    </table>

上面使用了两层循环,是为了显示forloop.parentloop的效果,其他效果只用看上面三行就行,后面六行都是重复的内容

下拉框-添加数据的示例

添加静态文件到settings

STATICFILES_DIRS = (
    os.path.join(BASE_DIR,"static"),
)
View Code

host.html中

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/commons.css" />
</head>
<body>
    <h2>业务线-对象</h2>
    <p>
        <input class="add" type="button" value="添加" />
    </p>
    <table border="1">
        <thead>
            <tr>
                <th>序号</th>
                <th>主机名</th>
                <th>主机ip</th>
                <th>主机端口</th>
                <th>部门</th>
            </tr>
        </thead>
        <tbody>
            {% for row in v1 %}
                <tr hid = "{{ row.id }}" bid = "{{ row.dept.id }}">
                    <td>{{ forloop.counter }}</td>
                    <td>{{ row.host }}</td>
                    <td>{{ row.ip }}</td>
                    <td>{{ row.port }}</td>
                    <td>{{ row.dept.dept }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    <div class="shade hide"></div>
    <div class="add-host hide">
        <form action="/host/" method="post">
            <p>
                <input class="group" type="text"  name="host" placeholder="主机名"/>
            </p>
            <p>
                <input class="group" type="text"  name="ip" placeholder="ip"/>
            </p>
            <p>
                <input class="group" type="text"  name="port" placeholder="端口号"/>
            </p>
            <p>
                <select name="dept_id">
                    {% for op in dept %}
                        <option value="{{ op.id }}">{{ op.dept }}</option>
                    {% endfor %}
                </select>
            </p>
            <p>
                <input type="submit" value="提交" />
                <input class="cancel" type="button" value="取消" />
            </p>
        </form>
    </div>

    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="/static/js.js"></script>
</body>
View Code

static中的css和js

#commons.css

.hide{
    display: none;
}
.shade {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background: black;
    opacity: 0.6;
    z-index: 100;
}
.add-host {
    width: 500px;
    height: 400px;
    position: fixed;
    left: 50%;
    top: 200px;
    background: white;
    z-index: 101;
    margin-left: -300px;
    text-align: center;

}

#js.js

$(function () {
    $(".add").click(function () {
        $(".shade,.add-host").removeClass("hide")
    })
    $(".cancel").click(function () {
        $(".shade,.add-host").addClass("hide")
    })
})
View Code

views.py

def host(request):
    if request.method == "GET":
        v1 = models.Host.objects.filter(id__gte=1)
        v2 = models.Host.objects.filter(id__gte=1).values("id","ip", "port", "dept_id","dept__dept")
        v3 =  models.Host.objects.filter(id__gte=1).values_list("id","ip", "port", "dept_id","dept__dept")
        dept = models.Bussines.objects.all()
        return render(request,"host.html",{"v1":v1,"v2":v2,"v3":v3,"dept":dept})
    elif request.method == "POST":
        h = request.POST.get("host")
        i = request.POST.get("ip")
        p = request.POST.get("port")
        d = request.POST.get("dept_id")
        models.Host.objects.create(host = h,ip = i,port = p,dept_id = d)
        return redirect("/host/")  //这里重新获取get请求,从而刷新页面

AJAX

数据验证

这里是在后台验证

模态对话框里提交表单的页面增加一个按钮,然后在jQuery里绑定事件

下面为绑定的事件

$(".ajax").click(function () {
        $.ajax({
            url:"/test/",
            type:"POST",
            data:{
                "host":$("#host").val(),
                "ip":$("#ip").val(),
                "port":$("#port").val(),
                "dept_id":$("#sel").val()},
            success:function (data) {
                if (data == "OK"){
                    location.reload()
                }
                else {
                    alert(data)
                    location.reload()
                }
            }
        })
    })

htm中添加一个按钮

在上个实例中只添加一个按钮

<p>
                <input type="submit" value="提交" />
                <input class="ajax" type="button" value="Ajax提交方式" />
                <input class="cancel" type="button" value="取消" />
            </p>
View Code

urls.py中修改

path('host/', views.host),
    path('test/', views.test),
View Code

views.py在上面的实例中只添加

def test(request):
    h = request.POST.get("host")
    i = request.POST.get("ip")
    p = request.POST.get("port")
    d = request.POST.get("dept_id")
    if h and len(h) > 5:
        models.Host.objects.create(host=h, ip=i, port=p, dept_id=d)
        return HttpResponse("OK")
    else:
        return HttpResponse("太短了") 

优化验证

上面的验证只是个很简单的验证,还没考虑类型是否满足数据库的要求。如果数据不符合数据库的数据格式,例如将端口号填写为字符串,此时程序就会报错,报错系统并不会崩溃,我们调试的时候可以看到错误信息,但是客户端是不知道发生了什么的。

下面就通过try来捕获异常,之后可以返回自定义的消息内容,或者也可以把异常信息返回

def test(request):
    import json
    dic = {"static":True,"error":None,"data":None}
    try:
        h = request.POST.get("host")
        i = request.POST.get("ip")
        p = request.POST.get("port")
        d = request.POST.get("dept_id")
        if h and len(h) > 5:
            models.Host.objects.create(host=h, ip=i, port=p, dept_id=d)
        else:
            dic["static"] = False
            dic["error"] = "太短了……"
    except Exception as e:
        dic["static"] = False
        dic["error"] = "请求错误……"
    return HttpResponse(json.dumps(dic))

上面返回都用HttpResponse()方式返回,并且返回的最好都是一个字典形式的

在提交按钮后面添加个span标签,用来提示用户,提示信息由后台提供

<p>
                <input type="submit" value="提交" />
                <input class="ajax" type="button" value="Ajax提交方式" />
                <input class="cancel" type="button" value="取消" />
                <span class=error style="color: red"></span>
            </p>

在AJAX验证中,修改下上个例子的判断

$(".ajax").click(function () {
        $.ajax({
            url:"/test/",
            type:"POST",
            data:{
                "host":$("#host").val(),
                "ip":$("#ip").val(),
                "port":$("#port").val(),
                "dept_id":$("#sel").val()},
            success:function (data) {
//data是服务器发送过来的数据,就是HttpResponse中的内容
//将字符串转为对象:字典 var data = JSON.parse(data) if (data.static){ location.reload() } else { $(".error").text(data.error) } } }) })

序列化返回的消息(JSON)

HttpResponse返回的内容是字符串,使用JSON序列化字符串,就可以返回更多的信息了,并且客户端处理起来也很方便。上面的例子已经这么做了。

1.先导入json模块

2.然后序列化字典    :   return HttpResponse(json.dumps(dic))

3.在jQ中处理字符串:使用 JSON.parse()  将字符串转为对象           var data = JSON.parse(data)

4.在jQ中可以直接使用data.key名   获取到值

示例-编辑功能

编辑页面和添加页面内容基本相同,只要把上面的添加复制过来稍加修改即可,样式用一样就行

<div class="edit-form hide">
        <form action="/host/" method="post" hid = "" >
            <p>
                <input type="text" name="id" style="display: none"  />
            </p>
            <p>
                <input type="text" name="host" placeholder="主机名"/>
            </p>
            <p>
                <input type="text" name="ip"  placeholder="ip"/>
            </p>
            <p>
                <input type="text"  name="port" placeholder="端口号"/>
            </p>
            <p>
                <select  name="dept_id">
                    {% for op in dept %}
                        <option value="{{ op.id }}">{{ op.dept }}</option>
                    {% endfor %}
                </select>
            </p>
            <p>
                <input class="ajax" type="button" value="编辑" />
                <input class="cancel" type="button" value="取消" />
            </p>
        </form>
    </div>

然后就是处理函数了


$(".edit").click(function () {
$(".shade,.edit-form").removeClass("hide");
//获取部门id
var bid = $(this).parent().parent().attr("bid");
//获取主机id
var hid = $(this).parent().parent().attr("hid");
$(".edit-form").find("select").val(bid);
$(".edit-form").find("input[name = 'id']").val(hid);
//获取编辑框中的值
var obj = $(this).parent().siblings("td").first();
//将表格中的值循环填入编辑框
$(".edit-form :text").each(function () {
$(this).val(obj.text());
obj = obj.next();
});
});
$(".ajax1").click(function () {
$.ajax({
url:"/edit/",
type:"POST",
//将edit-form表单的值打包发送到后台
data:$(".edit_form").serialize(),
success:function (data) {
//将字符串转为对象:字典
var data = JSON.parse(data)
console.log(data.static)
if (data.static){
location.reload()
}
else {
$(".error").text(data.error)
}
}
});

});
$(".cancel").click(function () {
$(".shade,.edit-form").addClass("hide")
});
 

点击编辑按钮,之后去掉隐藏的样式

因为是编辑,因此要获取到当前点击的hid和nid,这里可以通过点击编辑按钮是获取,因为在tr标签我们设置了hid和nid

然后添加一个带id的输入框,默认肯定是不能让用户修改的,隐藏把该标签隐藏掉

然后是下拉框,进入编辑页面,默认是要显示当前的部门的,这里可以通过bid来修改值,使其显示相应的部门

在使用Ajax时,我们有更简单的方式获取form表单的内容,就是使用serialize(),他可以将form表单的内容都打包一起

然后我们使用Ajax发送到后台

data:$(".edit-form").serialize(),

后台获取数据后处理如下

def edit(request):
    dic = {"static": True, "error": None, "data": None}
    try:
        id = request.POST.get("id")
        edit_data = {
            'host':request.POST.get("host"),
            'ip':request.POST.get("ip"),
            'port':request.POST.get("port"),
            'dept_id':request.POST.get("dept_id"),
        }
        for i ,j in edit_data.items():
            if j:
                models.Host.objects.filter(id = id).update(**edit_data)
            else:
                dic["static"] = False
                dic["error"] = "内容错误……"
    except Exception as e:
        dic["static"] = False
        dic["error"] = "内容错误……"
    return HttpResponse(json.dumps(dic))

url中添加

 path('edit/', views.edit),

示例-删除功能

上面的例子中已经添加了删除按钮,这里就不用改html了

只需要在js中处理点击删除按钮的操作

$('.delete').click(function () {
        var hid = $(this).parent().parent().attr('hid')
        $.ajax({
            url:"/delete/",
            type:"POST",
            //将edit-form表单的值打包发送到后台
            data:{"hid":hid},
            success:function (data) {
                //将字符串转为对象:字典
                var data = JSON.parse(data)
                console.log(data.static)
                if (data.static){
                    location.reload()
                }
                else {
                    $(".error").text(data.error)
                }
            }
        })
    });

先获取hid,然后将hid传给后台

在urls中添加

path('delete/', views.delete),

后台处理如下

def delete(request):
    dic = {"static": True, "error": None, "data": None}
    try:
        id = request.POST.get("hid")
        if id:
            models.Host.objects.filter(id=id).delete()
        else:
            dic["static"] = False
            dic["error"] = "内容错误……"
    except Exception as e:
        dic["static"] = False
        dic["error"] = "内容错误……"
    return HttpResponse(json.dumps(dic))

获取到nid,根据nid查找数据库相应的对象,删除掉

外键操作-多对多

多对多关系表的创建--两种方式

一般两种方式都用,自定义方式可以关联多个信息,自动创建的关联表只有三个属性:第三张表的id,host表的id,应用表的id

创建应用对应主机的关系表,一个应用可以属于多台主机,一个主机可以多个应用

先创建一个应用表

class Apply(models.Model):
    name = models.CharField(max_length=32)

然后创建主机和应用的关联表

1.自定义关系表

 class Host_to_apply(models.Model):
     hobj = models.ForeignKey(Host,to_field='id',on_delete=models.CASCADE)
     aobj = models.ForeignKey(Apply,to_field='id',on_delete=models.CASCADE)

2.自动创建关系表

通过创建应用表时自动创建

class Apply(models.Model):
    name = models.CharField(max_length=32)
    #  第二种方式
    r = models.ManyToManyField('Host')

自动创建只能帮我们创建一张3个字段的表:自增id,关联表的主键,被关联表的主键。如果想加额外的数据就只能用自定义关系表来创建额外的字段了。

设置关联关系

ORM都是通过类来进行数据库操作的。自定义关系表,直接可以获得结合表的类,直接操作结合表就可以进行数据库操作了

Host_to_apply.objects.create(aobj_id=1, hobj_id=1)

对于自动创建关联关系表,由于并没有结合表的类,无法直接对结合表进行操作。这里可以获取到对象,比如客户表id=1的那条数据对象,使用提供的方法对这个对象的关联系进行操作,添加、删除、清除、设置。

obj = Apply.objects.get(id=1)  # 先获取到一个对象,下面都是对id=1的关联关系进行操作
obj.r.add(1)  # 添加一个关系
obj.r.add(2, 3, 4)  # 多个参数添加多个关系
obj.r.add(*[2, 3, 4])  # 通过列表添加多个关系
obj.r.remove(1)  # 删除一个关系,同样支持多个参数或列表
obj.r.clear()  # 清除这个id的所有的关系
obj.r.set([3, 5, 7])  # 设置关系。这个id的其他关系都会清除,最后只有这个列表中的关系。相当于先清除在添加。这里没星号

上面没有获取的方法,获取的方法和之前获取数据的方法一样。models.Apply.objects 后面能使用什么方法,这里的obj就可以使用什么方法。比如:.all() 所有被关联的表的对象。all() 方法获取到的一定是一个QuerySet对象,在这里里面的每个元素是一个被关联的表 Apply 的对象。

多对多实例

应用到:查询,添加

 apply.html中

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/commons.css" />
</head>
<body>
    <h2>应用列表</h2>
    <p>
        <input class="add" type="button" value="添加" />
    </p>
    <table border="1">
        <thead>
            <tr>
                <th>应用名称</th>
                <th>应用主机名称</th>
            </tr>
        </thead>
        <tbody>
            {% for row in apply_list %}
                <tr aid = "{{ row.id }}" >
                    <td>{{ row.name }}</td>
                    <td>
                        {% for i in row.r.all %}
                            <span class="td">{{i.host}}</span>
                        {% endfor %}
                    </td>
                </tr>

            {% endfor %}
        </tbody>
    </table>
    <div class="shade hide"></div>
    <div class="add-host hide">
        <form action="/apply/" method="post">
            <p>
                <input id="name" class="group" type="text"  name="name" placeholder="应用名称"/>
            </p>
            <p>
                <select id="apply_name" name="apply_name" multiple>
                    {% for op in host_list %}
                        <option value="{{ op.id }}">{{ op.host }}</option>
                    {% endfor %}
                </select>
            </p>
            <p>
                <input class="ajax2" type="button" value="Ajax提交" />
                <input class="cancel" type="button" value="取消" />
                <span class=error style="color: red"></span>
            </p>
        </form>
    </div>

    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="/static/js.js"></script>
</body>
View Code

URLS.py中添加

path('apply/', views.apply),
View Code

js中添加


$(".add").click(function () {
$(".shade,.add-host").removeClass("hide")
});

$(".ajax2").click(function () {
$.ajax({
url:"/apply/",
type:"POST",
data:$(this).parent().parent().serialize(),
//data是服务器发送过来的数据,就是HttpResponse中的内容
datatype:JSON,//这里用jq获取就转为对象,下面就不需要在使用JSON.parse(data)
success:function (data) {
//将字符串转为对象:字典
if (data.static){
location.reload()
}
else {
$(".error").text(data.error)
}
},
error:function () {
//用来处理
}
});
});
$(".cancel").click(function () {
$(".shade,.add-host").addClass("hide")
});
datatype:JSON,//这里用jq获取就转为对象,下面就不需要在使用JSON.parse(data)

views.py

def apply(request):
    if request.method == 'GET':
        apply_list = models.Apply.objects.all()
        host_list = models.Host.objects.all()
        # for i in apply_list:
        #     print(i.name,i.r.all())
        return render(request, "apply.html", {'apply_list': apply_list, 'host_list': host_list})
    elif request.method == 'POST':
        dic = {"static": True, "error": None, "data": None}
        try:
            name = request.POST.get("name")
            host_list = request.POST.getlist('apply_name')
            if name:
                obj = models.Apply.objects.create(name = name)
                obj.r.add(*host_list)
            else:
                dic["static"] = False
                dic["error"] = "内容错误……"
        except Exception as e:
            dic["static"] = False
            dic["error"] = "内容错误……"
            print(e)
        return HttpResponse(json.dumps(dic))

 

posted @ 2018-12-28 12:43  Aline2  阅读(195)  评论(0编辑  收藏  举报