Django運維後臺的搭建之五:引入databases和django-crispy-forms
在上一篇,我們已經把我們做的運維外面套上了bootstrap框架,但是那僅僅是一個外殼,這一次是要把裏面的壤也扣上這樣的框架。
首先,編輯index.html,添加block元素,用於主頁存放不同的內容:
<div class="page-content"> <div class="page-content-area"> <div class="page-header"> <h1> <!--設置導航欄的頁面標題--> {% block page_title %} {% endblock %} <small> <i class="ace-icon fa fa-angle-double-right"></i> <!--設置導航欄的頁面子標題--> {{ sub_title }} </small> </h1> </div><!-- /.page-header --> <div class="row"> <div class="col-xs-12"> <!-- PAGE CONTENT BEGINS --> <!--設置頁面內容--> {% block container %} {% endblock %} <!-- PAGE CONTENT ENDS --> </div><!-- /.col --> </div><!-- /.row --> </div><!-- /.page-content-area --> </div><!-- /.page-content -->
之前在models.py裏我們設定了很多個項目,比如alionlineECS,alifuncECS等等,那麽對應每一個項目都會有一個html,在這裏我命名:alionlineECS_list.html用於存放“阿裏雲線上環境服務器”信息,alifuncECS_list.html用於“阿裏雲測試環境服務器”信息,ksonlineECS_list.html用於存放“金山雲線上環境服務器”信息,ksfuncECS_list.html用於“金山雲測試環境服務器”信息,同時修改index.html中Table下的鏈接,將其中的鏈接指向上面那些html們:
<ul class="submenu"> <li class=""> <a href="{% url ‘lists‘ table=‘alionlineECS‘ %}"> <i class="menu-icon fa fa-caret-right"></i> 阿裏雲線上環境服務器 </a> <b class="arrow"></b> </li> <li class=""> <a href="{% url ‘lists‘ table=‘alifuncECS‘ %}"> <i class="menu-icon fa fa-caret-right"></i> 阿裏雲測試環境服務器 </a> <b class="arrow"></b> </li> <li class=""> <a href="{% url ‘lists‘ table=‘ksonlineECS‘ %}"> <i class="menu-icon fa fa-caret-right"></i> 金山雲線上環境服務器 </a> <b class="arrow"></b> <li class=""> <a href="{% url ‘lists‘ table=‘ksfuncECS‘ %}"> <i class="menu-icon fa fa-caret-right"></i> 金山雲測試環境服務器 </a> <b class="arrow"></b> </li> </ul>
建立res_list.html放在之前的template文件夾裏,用來存放資源類表格,並把它作為一個模板,供其他頁面繼承,這樣可以節省大量的重復代碼。
<!--繼承index.html--> {% extends "index.html" %} {% block page_css %} {% endblock %} <!--填充導航欄的頁面名稱--> {% block page_title %} 基礎資料 {% endblock %} <!--放置主頁面內容--> {% block container %} {% load staticfiles %} <div class="row"> <!-- Search Page BEGINS--> <div class="col-xs-12"> <form class="navbar-for navbar-container" role="search" method="get" action="">{% csrf_token %} <!--放置搜索欄內容--> {% block search %} {% endblock %} <div class="col-sm-3"> <span class="input-group-btn"> <button type="submit" class="btn btn-purple btn-sm"> 查詢 <i class="ace-icon fa fa-search icon-on-right bigger-110"></i> </button> </span> </div> </form> </div> <!-- Search Page END --> <!-- PAGE TABLES BEGINS --> <div class="col-xs-12"> <div> <table id="table_id" class="table table-striped table-bordered table-hover"> <thead> <!--表格頭部--> {% block table_tr %} {% endblock %} <th> <!--最後一列作為添加數據按鈕--> <a class="blue" href="{% url ‘add‘ table=table %}"> <i class="ace-icon fa fa-search-plus bigger-130"></i> 添加數據 </a> </th> </thead> <!--表格內容--> <tbody> {% for item in data %} <tr> <!--通過for循環從data取出的具體表格內容--> {% block table_td %} {% endblock %} <td> <!--頁面擴展時的按鈕布局--> <div class="hidden-sm hidden-xs action-buttons"> <!--編輯信息按鈕--> <a class="green" href="{% url ‘edit‘ table item.id %}" title="編輯信息"> <i class="ace-icon fa fa-pencil bigger-130"></i> </a> <!--刪除信息按鈕--> <a class="red" href="{% url ‘delete‘ table item.id %}" title="刪除信息"> <i class="ace-icon fa fa-trash-o bigger-130"></i> </a> </div> <!--頁面收縮時的按鈕布局--> <div class="hidden-md hidden-lg"> <div class="inline position-relative"> <button class="btn btn-minier btn-yellow dropdown-toggle" data-toggle="dropdown" data-position="auto"> <i class="ace-icon fa fa-caret-down icon-only bigger-120"></i> </button> <ul class="dropdown-menu dropdown-only-icon dropdown-yellow dropdown-menu-right dropdown-caret dropdown-close"> <li> <a href="{% url ‘add‘ table=table %}" class="tooltip-info" data-rel="tooltip" title="添加數據"> <span class="blue"> <i class="ace-icon fa fa-search-plus bigger-120"></i> </span> </a> </li> <li> <a href="{% url ‘edit‘ table item.id %}" class="tooltip-success" data-rel="tooltip" title="修改信息"> <span class="green"> <i class="ace-icon fa fa-pencil-square-o bigger-120"></i> </span> </a> </li> <li> <a href="{% url ‘delete‘ table item.id %}" class="tooltip-error" data-rel="tooltip" title="刪除信息"> <span class="red"> <i class="ace-icon fa fa-trash-o bigger-120"></i> </span> </a> </li> </ul> </div> </div> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> {% endblock %} {% block page_javascript %} <!--datatable的專用js--> <script type="text/javascript"> $(document).ready(function () { $(‘#table_id‘).DataTable({ //分頁配置 "paging": false, //搜索配置 "searching": false, "bInfo": false, //列配置 "columnDefs": [{ //只有最後一行不需要排序 "orderable": false, "targets": -1 }] }); }); </script> {% endblock %}
alionlineECS_list.html,alifuncECS_list.html,slb_list.html等html文件繼承res_list.html,並將各自不一樣的內容在相應的block中進行填充,比如alionlineECS_list.html就是下面的樣子:
{% extends "res_list.html" %} {% block search %} {% endblock %} {% block table_tr %} <th>雲服務器名稱</th> <th>雲服務器類型</th> <th>雲服務器內網地址</th> <th>雲服務器外網地址</th> <th>雲服務器外網帶寬</th> <th>雲服務器配置</th> <th>備註</th> <th>登記人</th> {% endblock %} {% block table_td %} <td>{{ item.ecs_name }}</td> <td>{{ item.ecs_type }}</td> <td>{{ item.ecs_inip }}</td> <td>{{ item.ecs_outip }}</td> <td>{{ item.ecs_ipwidth }}</td> <td>{{ item.ecs_spec }}</td> <td>{{ item.ecs_remarks }}</td> <td>{{ item.ecs_signer }}</td> {% endblock %}
而slb_list.html就是這樣:
{% extends "res_list.html" %} {% block search %} {% endblock %} {% block table_tr %} <th>負載均衡名稱</th> <th>網絡類型</th> <th>轉發規則</th> <th>ip地址</th> <th>負載均衡協議</th> <th>前端端口</th> <th>後端端口</th> <th>負載均衡協議</th> <th>前端端口</th> <th>後端端口</th> <th>登記人</th> <th>備註</th> {% endblock %} {% block table_td %} <td>{{ item.slb_name }}</td> <td>{{ item.slb_type }}</td> <td>{{ item.slb_algorithm }}</td> <td>{{ item.slb_ip }}</td> <td>{{ item.slb_protocol }}</td> <td>{{ item.slb_fport }}</td> <td>{{ item.slb_bport }}</td> <td>{{ item.slb_protocol2 }}</td> <td>{{ item.slb_fport2 }}</td> <td>{{ item.slb_bport2 }}</td> <td>{{ item.slb_signer }}</td> <td>{{ item.slb_remarks }}</td> {% endblock %}
rds_list.html的代碼如下:
{% extends "res_list.html" %} {% block search %} {% endblock %} {% block table_tr %} <th>數據庫名稱</th> <th>數據庫類型</th> <th>mysql版本</th> <th>數據庫規格</th> <th>備註</th> <th>數據庫地址</th> <th>存儲空間</th> <th>登記人</th> {% endblock %} {% block table_td %} <td>{{ item.rds_name }}</td> <td>{{ item.rds_type }}</td> <td>{{ item.rds_mysql }}</td> <td>{{ item.rds_spec }}</td> <td>{{ item.rds_remark }}</td> <td>{{ item.rds_ip }}</td> <td>{{ item.rds_status }}</td> <td>{{ item.rds_signer }}</td> {% endblock %}
網頁代碼都準備好了,再往下的內容是修改views.py,把lists那個函數改成這樣:
def lists(request,table): #不同的需求跳到不同的界面 if table == ‘alionlineECS‘: data = alionlineECS.objects.all() list_template = ‘alionlineECS_list.html‘ sub_title = ‘阿裏雲線上環境服務器‘ if table == ‘alifuncECS‘: data = alifuncECS.objects.all() list_template = ‘alifuncECS_list.html‘ sub_title = ‘阿裏雲測試環境服務器‘ if table == ‘ksonlineECS‘: data = ksonlineECS.objects.all() list_template = ‘ksonlineECS_list.html‘ sub_title = ‘金山雲線上環境服務器‘ if table == ‘ksfuncECS‘: data = ksfuncECS.objects.all() list_template = ‘ksfuncECS_list.html‘ sub_title = ‘金山雲線上環境服務器‘ if table == ‘SLB‘: data = SLB.objects.all() list_template = ‘slb_list.html‘ sub_title = ‘負載均衡‘ if table == ‘RDS‘: data = RDS.objects.all() list_template = ‘rds_list.html‘ sub_title = ‘數據庫‘ #建立一個context,將值傳遞到對應的頁面 context = { ‘data‘: data, ‘table‘: table, ‘sub_title‘: sub_title, } #跳轉到相應頁面,並將具體的值傳遞過去 return render(request,list_template,context)
add的函數應該是這樣:
def add(request,table): #根據提交的請求不同,獲取來自不同Form的表單數據 if table == ‘alionlineECS‘: form = alionlineForm(request.POST or None) if table == ‘alifuncECS‘: form = alifuncForm(request.POST or None) if table == ‘ksonlineECS‘: form = ksonlineForm(request.POST or None) if table == ‘ksfuncECS‘: form = ksfuncForm(request.POST or None) if table == ‘SLB‘: form = SLBForm(request.POST or None) if table == ‘RDS‘: form = RDSForm(request.POST or None) #判斷form是否有效 if form.is_valid(): #創建實例,需要做些數據處理,暫不做保存 instance = form.save(commit=False) #將登錄用戶作為登記人 if table == ‘alionlineECS‘: instance.ecs_signer = request.user if table == ‘alifuncECS‘: instance.ecs_signer = request.user if table == ‘ksonlineECS‘: instance.ecs_signer = request.user if table == ‘ksfuncECS‘: instance.ecs_signer = request.user if table == ‘SLB‘: instance.slb_signer = request.user if table == ‘RDS‘: instance.rds_signer = request.user #保存該實例 instance.save() #跳轉至列表頁面 return redirect(‘lists‘,table=table) #創建context來集中處理需要傳遞到頁面的數據 context = { ‘form‘: form, ‘table‘: table, } #如果沒有有效提交,則仍留在原來頁面 return render(request,‘add.html‘,context)
同時,我們要添加兩個新的函數,一個叫edit,他的內容如下:
#修改數據,函數中的pk代表數據的id def edit(request,table,pk): if table == ‘alionlineECS‘: #這是Django的一個快捷方法,通過pk去line表中取值,如果有值則返回,如果無值則拋出http404的異常 #具體信息可參考https://docs.djangoproject.com/en/1.9/topics/http/shortcuts/ table_ins = get_object_or_404(alionlineECS,pk=pk) #通過instance來將Form的數據做填充 form = alionlineForm(request.POST or None,instance=table_ins) sub_title = ‘修改阿裏雲線上環境信息‘ if table == ‘alifuncECS‘: table_ins = get_object_or_404(alifuncECS,pk=pk) form = alifuncForm(request.POST or None,instance=table_ins) sub_title = ‘修改阿裏雲線上環境信息‘ if table == ‘ksonlineECS‘: table_ins = get_object_or_404(ksonlineECS,pk=pk) form = ksonlineForm(request.POST or None,instance=table_ins) sub_title = ‘修改金山雲線上環境服務器信息‘ if table == ‘ksfuncECS‘: table_ins = get_object_or_404(ksfuncECS,pk=pk) form = ksfuncForm(request.POST or None,instance=table_ins) sub_title = ‘修改金山雲測試環境服務器信息‘ if table == ‘SLB‘: table_ins = get_object_or_404(SLB,pk=pk) form = SLBForm(request.POST or None,instance=table_ins) sub_title = ‘修改負載均衡信息‘ if table == ‘RDS‘: table_ins = get_object_or_404(RDS,pk=pk) form = RDSForm(request.POST or None,instance=table_ins) sub_title = ‘修改數據庫信息‘ #判斷form是否有效 if form.is_valid(): #創建實例,需要做些數據處理,暫不做保存 instance = form.save(commit=False) #將登錄用戶作為登記人,在修改時,一定要使用str強制 if table == ‘alionlineECS‘: instance.ecs_signer = str(request.user) if table == ‘alifuncECS‘: instance.ecs_signer = str(request.user) if table == ‘ksonlineECS‘: instance.ecs_signer = str(request.user) if table == ‘ksfuncECS‘: instance.ecs_signer = str(request.user) if table == ‘SLB‘: instance.slb_signer = str(request.user) if table == ‘RDS‘: instance.rds_signer = str(request.user) #保存該實例 instance.save() #跳轉至列表頁面,配合table參數,進行URL的反向解析 return redirect(‘lists‘, table=table) context = { ‘table‘: table, ‘form‘: form, ‘page_title‘: ‘基礎資料‘, ‘sub_title‘: sub_title, } #與res_add.html用同一個頁面,只是edit會在res_add頁面做數據填充 return render(request,‘res_add.html‘,context)
另一個函數是delete,這個是用來刪除的,內容如下:
#刪除操作 def delete(request,table,pk): #選擇相應的表格 if table == ‘alionlineECS‘: #通過id值獲取相應表格的實例,有值則返回,無值則拋出異常 table_ins = get_object_or_404(alionlineECS,pk=pk) if table == ‘alifuncECS‘: table_ins = get_object_or_404(alifuncECS,pk=pk) if table == ‘ksonlineECS‘: table_ins = get_object_or_404(ksonlineECS,pk=pk) if table == ‘ksfuncECS‘: table_ins = get_object_or_404(ksfuncECS,pk=pk) if table == ‘SLB‘: table_ins = get_object_or_404(SLB,pk=pk) if table == ‘RDS‘: table_ins = get_object_or_404(RDS,pk=pk) #接收通過AJAX提交過來的POST if request.method == ‘POST‘: #刪除該條目 try: table_ins.delete() #刪除成功,則data信息為success data = ‘success‘ except IntegrityError: #如因外鍵問題,或其他問題,刪除失敗,則報error data = ‘error‘ #將最後的data值傳遞至JS頁面,進行後續處理,safe是將對象序列化,否則會報TypeError錯誤 return JsonResponse(data,safe=False)
別忘了這裏還要修改一下主urls.py,添加edit和delete:
from django.conf.urls import url,include from django.contrib import admin import Online.views admin.autodiscover() from Online import views as Online_views urlpatterns = [ url(r‘^admin/‘,admin.site.urls), url(r‘^lists/(?P<table>\w+)/$‘,Online.views.lists,name=‘lists‘), url(r‘^add/(?P<table>\w+)/$‘,Online.views.add,name=‘add‘), #基礎資料的顯示 #修改數據,?P<pk>\d+代表穿過來的id值,且id值一定為數字 url(r‘^edit/(?P<table>\w+)/(?P<id>\d+)/$‘,Online.views.edit,name=‘edit‘), #刪除數據 url(r‘^delete/(?P<table>\w+)/(?P<pk>\d+)/$‘,Online.views.delete,name=‘delete‘), url(r‘^index/‘,Online.views.index,name=‘index‘), url(r‘^login/‘,include(‘Online.urls‘)), ]
啟動django,在瀏覽器裏輸入"外網地址:8000/lists/slb"就發現原來那個白色的界面已經運用了boostrap模板,如下:
而打開"外網地址:8000/lists/alionlineECS",對應阿裏區線上環境的資料也是套用了boostrap模板:
當你點擊“添加數據”的時候,界面也是會正確轉向的:
但是這個增加的頁面很難看,白白的底兒,很挫,我們也希望這個增加的界面也有模板的樣子。於是這裏要用一個django-crispy-forms的app,首先在服務器裏,使用#pip install --upgrade django-crispy-forms下載並安裝。
然後在settings.py中加入相關app,並使其使用bootstrap3的前端。修改settings.py如下:
INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ‘Online‘, ‘SLB‘, ‘RDS‘, #crispy app 把這個APP添加進去 ‘crispy_forms‘, ]
然後還要在settings.py後面追加下面一句話:
#App settings CRISPY_TEMPLATE_PACK = ‘bootstrap3‘
再修改add.html文件,把crispy.form應用進去:
<!--引用crispy-forms標簽--> {% load crispy_forms_tags %} <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <form method=‘POST‘ action=‘‘>{% csrf_token %} <!--將crispy-forms應用到form中--> {{ form | crispy }} <input type=‘submit‘ value=‘提交‘ /> </form> </body> </html>
然後再返回來看看添加的界面,嗯,好像變樣了:
我們現在為了統一,把add.html改成res_add.html,同時繼承index.html,將res_add.html中的內容填充到index的Container block。
{% extends "index.html" %} <!--引用crispy-forms標簽--> {% load crispy_forms_tags %} {% block page_title %} 基礎資料 {% endblock %} {% block container %} <div class="row"> <div class="col-sm-3 pull-left"> <form method=‘POST‘ action=‘‘>{% csrf_token %} <!--將crispy-forms應用到form中--> {{ form | crispy}} <input class=‘btn btn-primary‘ type=‘submit‘ value=‘提交‘ /> <a href="{% url ‘lists‘ table=table %} "><input class=‘btn btn-default‘ type=‘button‘ value=‘取消‘ /></a> </form> </div> </div> {% endblock %}
然後再把views.py裏面add函數裏面最後那一行
return render(request,‘add.html‘,context)
改成
return render(request,‘res_add.html‘,context)
至此,整個添加界面就全部繼承過來了:
本文出自 “生活就是等待戈多” 博客,請務必保留此出處http://chenx1242.blog.51cto.com/10430133/1952685
Django運維後臺的搭建之五:引入databases和django-crispy-forms