Django(四) ORM 外鍵操做及初識Ajax

1、內容回顧

一、Django請求的生命週期:

​ 路由系統 -> 視圖函數(獲取模板+數據 -> 渲染) -> 字符串返回給用戶html

二、路由系統:

/index/                #->  函數或類.as_view()
/detail/(\d+)          #->  函數(參數) 或 類.as_view()(參數)
/detail/(?P<nid>\d+)   #->  函數(參數) 或 類.as_view()(參數)
/detail/               #->  include("app01.urls")
/detail/    name='a1'  #->  include("app01.urls")
                       #->  視圖中:reverse
                       #->  模板中:{% url "a1" %}

 

三、視圖:

FBV:函數前端

def index(request,*args,**kwargs):

 

CBV:類python

class Home(views.View):
    def get(self,reqeust,*args,**kwargs):

獲取用戶請求中的數據:mysql

request.POST.get
request.GET.get
reqeust.FILES.get()


# checkbox,select

........getlist()

文件對象jquery

文件對象 = reqeust.FILES.get()
文件對象.name
文件對象.size
文件對象.chunks()  # 直接循環文件對象也能夠

# 特殊的設置 <form action="/login/" method="POST" enctype="multipart/form-data">

給用戶返回數據:ajax

render(request, "模板文件路徑", {'k1': [1,2,3,4],"k2": {'name': 'lgeng','age': 73}})
redirect("URL")   
HttpResponse('字符串')   

 

四、模板語言

render(request, "模板路徑", {'obj': 1234, 'k1': [1,2,3,4],"k2": {'name': 'lgeng','age': 22}})

 

<html>
<body>
<h1> {{ obj }} </h1>      # 取變量值
<h1> {{ k1.3 }} </h1>     # 取列表的值
<h1> {{ k2.name }} </h1>  # 取字典的值

{% for i in k1 %}       # 循環列表的值
<p> {{ i }} </p>          # 取值
{% endfor %}{% for row in k2.keys %}  # 循環取字典key
{{ row }}        # 取值
{% endfor %}{% for row in k2.values %} # 循環取字典values
{{ row }}        # 取值
{% endfor %}{% for k,v in k2.items %}  # 循環取key、values
{{ k }} - {{v}}  # 取值
{% endfor %}
# 注意:模板語言循環keys、values、items這裏不加 "()"
</body>
</html>

 

五、ORM

  • a. 建立類和字段
class User(models.Model):
    age = models.IntergerFiled()            # 整數在後面加長度不起做用
    name = models.CharField(max_length=10)  # 字符長度

# 生成數據庫結構命令
Python manage.py makemigrations
python manage.py migrate

# settings.py 配置 註冊APP

 

  • b. 操做
#
models.User.objects.create(name='qianxiaohu',age=18) # 第一種
dic = {'name': 'xx', 'age': 19}                      # 第二種
models.User.objects.create(**dic)    # **dic
obj = models.User(name='xiao',age=18)                # 第三種
obj.save()
#
models.User.objects.filter(id=1).delete()
#
models.User.objects.filter(id__gt=1).update(name='alex',age=84)
dic = {'name': 'xx', 'age': 19}
models.User.objects.filter(id__gt=1).update(**dic)
#
models.User.objects.filter(id=1,name='root')
models.User.objects.filter(id__gt=1,name='root')# 大於
models.User.objects.filter(id__lt=1)            # 小於
models.User.objects.filter(id__gte=1)           # 大於等於
models.User.objects.filter(id__lte=1)           # 小於等於

models.User.objects.filter(id=1,name='root')
dic = {'name': 'xx', 'age__gt': 19}
models.User.objects.filter(**dic)  # 這裏也能夠傳字典,增刪改查均可以加字典

 

2、Django ORM 外鍵操做一對多

a.一、建立一對多表結構

class Business(models.Model):
    # id
    caption = models.CharField(max_length=32)
    code = models.CharField(max_length=32,null=True,default="SA")
    # 新增列 容許爲空null=True 或 default="SA",就不會提示信息

class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)  # 加上索引
    ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field='id')  # 表中生成列名:b_id
    # b = models.ForeignKey("Business", to_field='id')   # 外鍵約束,
    # b = models.ForeignKey("Business")   #只寫表名,默認與那張表主鍵關聯

# 外鍵:
#   v = models.Host.objects.filter(nid__gt=0)
#   v[0].b.caption  #---->  經過.進行跨表

 

a.2 獲取單表數據的三種方式

v1 = models.Business.objects.all() #QuerySet類型 ,內部元素都是對象(對象內相似字典結構)
v2 = models.Business.objects.all().values('id','caption') #QuerySet ,內部元素都是字典 
v3 = models.Business.objects.all().values_list('id','caption') #QuerySet ,內部元素都是元組
#===============
models.Business.objects.get(id=1) #獲取到的一個對象,若是不存在就報錯
obj = models.Business.objects.filter(id=1).first() #對象或者None

 

a.三、示例:展現業務線

urls.pysql

from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^business$', views.business),
]

 

views.py數據庫

from django.shortcuts import render, redirect, HttpResponse
from app01 import models

def business(request):
    v1 = models.Business.objects.all()
    # QuerySet
    # [obj(id,caption,code), obj(id,caption,code), obj(id,caption,code)]

    v2 = models.Business.objects.values('id','caption')
    # QuerySet
    # [{'id':1,'caption':'運維'},{'id':1,'caption':'運維'},{'id':1,'caption':'運維'}]

    v3 = models.Business.objects.values_list('id','caption')
    # QuerySet
    # [(1,運維),(2,開發)]

    return render(request, "business.html", {'v1':v1,'v2':v2 ,'v3':v3})

 

business.htmldjango

<body>
    <h1>業務線列表(對象)</h1>
    <ul>
        {% for row in v1 %}
            <li>{{ row.id }} - {{ row.caption }} - {{ row.code }}</li>
        {% endfor %}
    </ul>

    <h1>業務線列表(字典)</h1>
    <ul>
        {% for row in v2 %}
            <li>{{ row.id }} - {{ row.caption }}</li>
        {% endfor %}
    </ul>

    <h1>業務線列表(元組)</h1>
    <ul>
        {% for row in v3 %}
            <li>{{ row.0 }} - {{ row.1 }}</li>
        {% endfor %}
    </ul>
</body>

 


b.一、一對多跨表操做

必定要注意:「.」和「__」跨表,在不一樣場景的應用。json

點跨表,點的是對象,雙下劃線,是在filter裏的字符串中。

b.二、一對多塊表操做的的三種方式

具體用法看示例,及註釋

b.三、示例:host主機列表

urls.py

url(r'^host$', views.host),
  • 1

views.py

def host(request):
    v1 = models.Host.objects.filter(nid__gt=0)  # 同 all()
    # QuerySet [host 對象,]
    for row in v1:
        print(row.nid,row.b_id,row.b.caption,sep='\t')  # 注意 row.b.caption 的含義
    # 注意:這裏經過"__"雙下劃線跨表。'b__caption'
    v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
    # QuerySet: [ {} ]
    print(v2)
    for row in v2:
        print(row['nid'], row['hostname'],row['b_id'], row['b__caption'])
    # 注意:這裏經過"__"雙下劃線跨表。'b__caption'
    v3= models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption')
    # QuerySet: [ () ]

    b_list = models.Business.objects.all()
    return render(request, 'host.html', {'v1':v1, 'v2':v2, 'v3':v3, 'b_list':b_list})

host.html

<body>
    <h1>主機列表(對象)</h1>
    <table border="1">
        <thead>
            <tr>
                <th>主機名</th>
                <th>IP</th>
                <th>端口</th>
                <th>業務線名稱</th>
            </tr>
        </thead>
        <tbody>
            {% for row in v1 %}
                <tr hid="{{ row.nid }}" bid="{{ row.b.id }}">
{#                主機id不須要讓用戶看見,但修改時又須要,因此自定義個屬性#}
                    <td>{{ row.hostname }}</td>
                    <td>{{ row.ip }}</td>
                    <td>{{ row.port }}</td>
                    <td>{{ row.b.caption }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    <hr>
    <h1>主機列表(字典)</h1>
    <table border="1">
        <thead>
            <tr>
                <th>主機名</th>
                <th>業務線名稱</th>
            </tr>
        </thead>
        <tbody>
            {% for row in v2 %}
                <tr hid="{{ row.nid }}" bid="{{ row.b.id }}">
                    <td>{{ row.hostname }}</td>
                    <td>{{ row.b__caption }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    <hr>
    <h1>主機列表(元組)</h1>
    <table border="1">
        <thead>
            <tr>
                <th>主機名</th>
                <th>業務線名稱</th>
            </tr>
        </thead>
        <tbody>
            {% for row in v3 %}
                <tr hid="{{ row.0 }}" bid="{{ row.2 }}">
                    <td>{{ row.1 }}</td>
                    <td>{{ row.3 }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
</body>

 

c、增長一對多數據示例

若是前端展現序號的話,模板語言for循環那裏有幾個點能夠實現。

{% for row in v1 %}           # 假設3條數據
    {{ forloop.counter}}      # 依次爲:一、二、3
    {{ forloop.counter0}}     # 依次爲:0、一、2
    {{ forloop.revcounter}}   # 依次爲:三、二、1
    {{ forloop.revcounter0}}  # 依次爲:二、一、0
    {{ forloop.last }}        # 是否最後一個,是爲True,其餘False
    {{ forloop.first }}       # 是否第一個
    {{ forloop.parentloop }}  # 嵌套循環,表示上層循環的上面的六個值分別是多少。
{% endfor %}

 

CSS 知識點position回顧:

  • fixed :生成絕對定位的元素,相對於瀏覽器窗口進行定位。元素的位置經過 「left」, 「top」, 「right」 以及 「bottom」 屬性進行規定。

  • relative :生成相對定位的元素,相對於其正常位置進行定位。所以,」left:20」 會向元素的 LEFT 位置添加 20 像素。

  • absolute :生成絕對定位的元素,相對於第一個父元素進行定位 (static 定位除外外)。元素的位置經過 「left」, 「top」, 「right」 以及 「bottom」 屬性進行規定。


上面的b.3示例,views裏host函數,修改成:

def host(request):
    if request.method == "GET":
        v1 = models.Host.objects.filter(nid__gt=0)
        v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
        v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption')

        b_list = models.Business.objects.all()

        return render(request, 'host.html', {'v1': v1,'v2': v2,'v3': v3,'b_list':b_list})

    elif request.method == "POST":

        h = request.POST.get('hostname')
        i = request.POST.get('ip')
        p = request.POST.get('port')
        b = request.POST.get('b_id')

        models.Host.objects.create(hostname=h,
                                   ip=i,
                                   port=p,
        # b=models.Business.objects.get(id=b)  # 效果同樣,只是多了一次數據庫查詢操做
                                   b_id=b
                                   )
        # renturn render(request, 'host.html')  # 每次post提交都會有刷新操做
        # 使用render須要返回模板數據,if條件裏的代碼再寫一遍,爲了提升重用性,讓用戶再次訪問。
        return redirect('/host')

 

host.html (部分與上面重複的代碼略,行數太多,有些合併爲一行了),須要加載jQury。

<head>
    <style>
        .hide{ display: none; }
        .shade{
            position: fixed;
            top: 0; right: 0; left: 0; bottom: 0;
            background: black;
            opacity: 0.6; z-index: 100;
        }
        .add-modal{
            position: fixed;
            height: 300px; width: 400px; margin-left: -200px; top:100px; left: 50%;
            background: white; border: 1px solid red;
            z-index: 101;
        }
    </style>
</head>
<body>
    <h1>主機列表(對象)</h1>
    <div>
        <input id="add_host" type="button" value="添加" />
    </div>
    <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.nid }}" bid="{{ row.b_id }}">
                        <td>{{ forloop.counter }}</td>
                        <td>{{ row.hostname }}</td>
                        <td>{{ row.ip }}</td>
                        <td>{{ row.port }}</td>
                        <td>{{ row.b.caption }}</td>
                    </tr>
                {% endfor %}
        </tbody>
    </table>

    <div class="shade hide"></div>
    <div class="add-modal hide">
        <form method="POST" action="/host">
            <div class="group">
                <input id="host" type="text" placeholder="主機名" name="hostname" />
            </div>
            <div class="group">
                <input id="ip" type="text" placeholder="IP" name="ip" />
            </div>
            <div class="group">
                <input id="port" type="text" placeholder="端口" name="port" />
            </div>
            <div class="group">
                <select id="sel" name="b_id">
                    {% for op in b_list %}
                    <option value="{{ op.id }}">{{ op.caption }}</option>
                    {% endfor %}
                </select>
            </div>
            <input type="submit" value="提交" />
            <input id="cancel" type="button" value="取消" />
        </form>
    </div>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function(){  // 框架加載完後,自執行

            $('#add_host').click(function(){
                $('.shade,.add-modal').removeClass('hide');
            });

            $('#cancel').click(function(){
                $('.shade,.add-modal').addClass('hide');
            });
        });
    </script>
</body>

 

d、初識Ajax

上面是經過模態對話框實現的,可是有個弊端,就是彈出框裏一點提交,頁面確定會刷新。若是用戶輸錯,應該顯示錯誤提示,而不是刷新頁面

因此但願有個功能能夠用戶輸完以後,悄悄發送數據給後臺,頁面不刷新。後臺拿到以後再給個回覆。

悄悄提交,用Ajax提交。

這裏Ajax 用jQuery來實現。jquery依賴於xml http request 對象來發的。

$.ajax({
    url: '/host',                    // 提交地址
    type: "POST",                    // 提交方式
    data: {'k1': 123,'k2': "root"},  // 提交數據
    success: function(data){         // data是服務器端返回的字符串
        // 等服務器返回數據後,自動觸發這個函數
        var obj = JSON.parse(data);  // 把字符串轉換成對象
    }
})

 

Ajax請求return 用HttpResponse

  • obj = JSON.parse(data) 把字符串轉換成對象
  • JSON.stringfy(obj) 前端把對象轉換成字符串

host.html 添加:

    <form id="add_form" method="POST" action="/host">
             .
             ..
             ...
            <input type="submit" value="提交" />
            <a id="ajax_submit" >悄悄提交</a>
            <input id="cancel" type="button" value="取消" />
            <span id="erro_msg" style="color: red"></span>
    </form>
    <script>
            $('#ajax_submit').click(function(){
                $.ajax({
                    url: "/test_ajax",
                    type: 'POST',
                    //data: {'hostname': $('#host').val(), 'ip': $('#ip').val(), 'port': $('#port').val(), 'b_id': $('#sel').val()},
                    data: $('#add_form').serialize(),  // 同上面那一句
                    success: function(data){
                        var obj = JSON.parse(data);
                        if(obj.status){
                            location.reload();;  // JS刷新當前頁面
                        }else{
                            $('#erro_msg').text(obj.error);
                        }
                    }
                })
            });
    </script>

 

 

urls.py

url(r'^test_ajax$', views.test_ajax),

 

  • 1

views.py

def test_ajax(request):
    import json
    ret = {'status': True, 'error': None, 'data': None}
    try:
        h = request.POST.get('hostname')
        i = request.POST.get('ip')
        p = request.POST.get('port')
        b = request.POST.get('b_id')
        if h and len(h) > 5:
            models.Host.objects.create(hostname=h, ip=i, port=p, b_id=b)
        else:
            ret['status'] = False
            ret['error'] = "過短了"
    except Exception as e:
        ret['status'] = False
        ret['error'] = '請求錯誤'
    return HttpResponse(json.dumps(ret))

 

除了$.ajax ,還有$.get$.post$.getJson等等,這些方法內部都是調用$.ajax

$.get本質上就是type寫成get。$.get(url="xxx", data={}, success……)

e、編輯一對多示例

刪除數據的話,能夠後臺刪除數據而且頁面直接remove掉相應的顯示內容,這樣頁面就不用刷新了。

修改下面主要是獲取select下拉框的值作獲取修改

    <div class="edit-modal hide">
        <form id="edit_form" method="POST" action="/host">
                <input type="text" name="nid" style="display:none" />
          <!--在用戶點編輯的一剎那,獲取的nid放在這,提交給後臺是那條id的數據。-->
                <input type="text" placeholder="主機名" name="hostname" />
                <input type="text" placeholder="IP" name="ip" />
                <input  type="text" placeholder="端口" name="port" />
                <select name="b_id">
                    {% for op in b_list %}
                    <option value="{{ op.id }}">{{ op.caption }}</option>
                    {% endfor %}
                </select>
            <a id="ajax_submit_edit" >確認編輯</a>
        </form>
    </div>

    <script>
            $('.edit').click(function(){
                $('.shade,.edit-modal').removeClass('hide');

                var bid = $(this).parent().parent().attr('bid');
                var nid = $(this).parent().parent().attr('hid');

                $('#edit_form').find('select').val(bid);
                $('#edit_form').find('input[name="nid"]').val(nid);

                // 修改
                $.ajax({
                    data: $('#edit_form').serialize()
                });
                // models.Host.objects.filter(nid=nid).update()
            })
    </script>

 

3、Django ORM 外鍵操做 多對多

假設目前有兩張表,主機表和應用表,

class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
    port = models.IntegerField()

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

 

一個主機能夠對應多個應用、一個應用也可對應多個主機。多個一對多,即多對多

一、建立多對多

  • 方式一:自定義關係表

建立第三張關係表。

class HostToApp(models.Model):
    hobj = models.ForeignKey(to='Host',to_field='nid')
    aobj = models.ForeignKey(to='Application',to_field='id')

 

  • 方式二:自動建立關係表

表中添加 ManyToManyField

class Application(models.Model):
    name = models.CharField(max_length=32)
    r = models.ManyToManyField("Host")

 

這樣第三張表Django就幫咱們建立了。這裏表名爲 app01_application_r ,這裏寫了兩個類生成三張表。

總結:通常用哪一種方式?

自動建立關係表,表中只能建立三列數據。想增長額外的列作不到。對於自定義的,自定製功能更好些。

二、多對多關係表中添加數據

  • 方式一:自定義關係表

這種添加數據比較簡單,就是表中添加數據那樣。典型的 使用類操做數據庫

models.User.objects.create(hobj_id=1,aobj_id=2)

 

  • 方式二:自動建立的關係表

上面是使用類操做數據庫,可是這裏自動建立的關係表,沒有類,就不能經過類直接操做數據庫。

因此只能經過裏面定義的r進行間接操做。

和以前操做同樣,獲取到r:

obj = models.Application.objects.get(id=1)  # 獲取id爲1的application對象
obj.name    # 應用名
obj.r       # 獲取到 r 

 

獲取到r,裏面有哪些功能呢?

obj = models.Application.objects.get(id=1) 
# 增長數據
obj.r.add(1)            # 添加application id爲1,host id也是1
obj.r.add(2)            # 添加application id爲1,host id也是2
obj.r.add(2,3,4)        # 增長多條關係1 2,1 3 ,1 4
obj.r.add(*[1,2,3,4])   # 增長列表,增長多條關係1 1 ,1 2,1 3 ,1 4
# 刪除數據
obj.r.remove(1)         # 刪除 1 1 記錄
obj.r.remove(2,4)       # 刪除 1 2,1 4 記錄
obj.r.remove(*[1,2,3])  # 經過列表刪除

obj.r.clear()           # 刪除application id爲1的因此數據
# 更新、修改數據(注意這裏列表不加*)
obj.r.set([3,5,7])      # 只存在1 3,1 5,1 7。application id=1的其餘都沒有了

# 查詢數據
obj.r.all()             # 全部application id=1的主機對象 「列表」QuerySet類型

 

三、多對多數據增長示例

views.py

def app(request):
    if request.method == "GET":
        app_list = models.Application.objects.all()
        host_list = models.Host.objects.all()
        return render(request,'app.html',{"app_list": app_list,'host_list': host_list})
    elif request.method == "POST":
        app_name = request.POST.get('app_name')
        host_list = request.POST.getlist('host_list')
        print(app_name,host_list)
        # 建立完以後會返回一個對象。對象就是你增長的這條數據的對象。
        obj = models.Application.objects.create(name=app_name)
        obj.r.add(*host_list)
        return redirect('/app')

def ajax_add_app(request):
    ret = {'status':True, 'error':None, 'data': None}
    app_name = request.POST.get('app_name')
    host_list = request.POST.getlist('host_list')
    obj = models.Application.objects.create(name=app_name)
    obj.r.add(*host_list)
    return HttpResponse(json.dumps(ret))

 

urls.py

url(r'^app$', views.app),
url(r'^ajax_add_app$', views.ajax_add_app),

 

app.html

    <div class="add-modal hide">
        <form id="add_form" method="POST" action="/app">
            <div class="group">
                <input id="app_name" type="text" placeholder="應用名稱" name="app_name" />
            </div>
            <div class="group">
                <select id="host_list" name="host_list" multiple>
                <!--這裏,示例中增長數據,以前是單選的,多對多這裏要改爲多選的。multiple-->
                    {% for op in host_list %}
                        <option value="{{ op.nid }}">{{ op.hostname }}</option>
                    {% endfor %}
                </select>
            </div>
            <input type="submit" value="提交" />
            <input id="add_submit_ajax" type="button" value="Ajax提交" />
        </form>
    </div>

    <script>
                $('#add_submit_ajax').click(function(){
                $.ajax({
                    url: '/ajax_add_app',
                    // data: {'user': 123,'host_list': [1,2,3,4]},
                    data: $('#add_form').serialize(),
                    type: "POST",
                    dataType: 'JSON', // 內部
                    traditional: true,  // 獲取到普通字符和列表,不然列表發不到後臺
                    success: function(obj){
                        console.log(obj);
                    },
                    error: function () {  // 發到後臺後臺沒有捕捉到,執行的錯誤
                    }
                })
            });
      </script>

 

下拉框select,默認val獲取單值,若是設了multiple,獲取的就是列表。

 


轉載請務必保留此出處:http://www.cnblogs.com/lgeng/articles/7365134.html 

<!-- END  -->

 

 

 

 

《版權說明》: 本文轉自-- http://blog.csdn.net/fgf00/article/details/53812643

相關文章
相關標籤/搜索