Django运维后台的搭建之三:用url去精细定制与反向解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django运维后台的搭建之三:用url去精细定制与反向解析相关的知识,希望对你有一定的参考价值。

上一篇文章里,我们做了一个alionlineecs(阿里云线上环境服务器)的添加界面,但是要知道我们的计划里是有六个分支的,而alionlineecs仅仅是其中之一,要是每一个都这么写的话,那么views.py肯定又臭又长,充满了大量的复制片段。


对于这样的情况,我们就用一种统一的方式,把这些alionlineecs\alifuncecs\slb\rds等等这些分支当成一个变量,再自定义两个url,比如lists这个url就是展示功能,当在浏览器里输入"外网地址:8000/lists/alionlinecs"的时候,就会出现阿里线上环境服务器的展示界面;当在浏览器里输入"外网地址:8000/lists/slb"的时候,就会出现阿里负载均衡的展示界面。同时也额外设定一个add的url,当在浏览器里输入"外网地址:8000/add/alionlinecs"的时候,就会出现阿里线上环境服务器的添加界面。这样就同意好管理多了。


于是我们先编辑vim forms.py:

# -*- coding: UTF-8 -*-  
from django.forms import ModelForm
from .models import alionlineECS,alifuncECS,ksonlineECS,ksfuncECS,SLB,RDS
#定义ECS的Form,Form名字为 模式名+Form
class alionlineForm(ModelForm):
    #自定义ModelForm的内容
    class Meta:
        #该ModelForm参照Model: ECS
        model = alionlineECS
        #在Form中不显示node_signer这个字段  
        exclude = [‘ecs_signer‘]
        
class alifuncForm(ModelForm):
    class Meta:
        model = alifuncECS
        exclude = [‘ecs_signer‘]
        
class ksonlineForm(ModelForm):
    class Meta:
        model = ksonlineECS
        exclude = [‘ecs_signer‘]
        
class ksfuncForm(ModelForm):
    class Meta:
        model = ksfuncECS
        exclude = [‘ecs_signer‘]
        
class SLBForm(ModelForm):
    class Meta:
        model = SLB
        exclude = [‘slb_signer‘]
        
class RDSForm(ModelForm):
    class Meta:
        model = RDS
        exclude = [‘rds_signer‘]


然后把urls.py进行一下整顿:

from django.conf.urls import url
from django.contrib import admin
import 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‘),
]


最麻烦的地方就是views.py,这个变动比较大了:

# -*- coding: UTF-8 -*-
from django.shortcuts import render,redirect
from .models import alionlineECS,alifuncECS,ksonlineECS,ksfuncECS,SLB,RDS
from forms import alionlineForm,alifuncForm,ksonlineForm,ksfuncForm,SLBForm,RDSForm
def lists(request,table):
        #不同的需求跳到不同的界面
        if table == ‘alionlineECS‘:
        data = alionlineECS.objects.all()
        list_template = ‘alionlineECS_list.html‘
    if table == ‘alifuncECS‘:
        data = alifuncECS.objects.all()
        list_template = ‘alifuncECS_list.html‘
    if table == ‘ksonlineECS‘:
        data = ksonlineECS.objects.all()
        list_template = ‘ksonlineECS_list.html‘
    if table == ‘ksfuncECS‘:
        data = ksfuncECS.objects.all()
        list_template = ‘ksfuncECS_list.html‘
    if table == ‘SLB‘:
        data = SLB.objects.all()
        list_template = ‘slb_list.html‘
    if table == ‘RDS‘:
        data = RDS.objects.all()
        list_template = ‘rds_list.html‘
        #建立一个context,将值传递到对应的页面
    context = {
        ‘data‘:data,
    }
        #跳转到相应页面,并将具体的值传递过去
    return render(request,list_template,context)
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,
    }
    #如果没有有效提交,则仍留在原来页面  
    return render(request, ‘add.html‘,context)


上面我们写了很多个html,那么现在就要一个一个的补全这些html,比如alionlineECS_list.html,这里放上我们需要对外展示的节点,注意要跟model.py的各项一一对应:

    <meta charset="UTF-8">  
    <title></title>  
</head>
<body>
    <table>
        <tr>
            <th>云服务器名称</th>
            <th>云服务器类型</th>
            <th>云服务器内网地址</th>
            <th>云服务器外网地址</th>
            <th>云服务器外网带宽</th>
            <th>云服务器配置</th>
            <th>备注</th>
            <th>登记人</th>
        </tr>
        {% for item in data %}
            <tr>
                <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>
            </tr>
        {% endfor %}
    </table>
</body>
</html>


而SLB.html就长这个样子:

<!DOCTYPE html>
<html>
<head lang="en">  
    <meta charset="UTF-8">  
    <title></title>  
</head>
<body>
    <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>
        </tr>
        {% for item in data %}
            <tr>
                <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>
            </tr>
        {% endfor %}
    </table>
</body>
</html>


RDS.html写成这个样子:

<!DOCTYPE html>
<html>
<head lang="en">  
    <meta charset="UTF-8">  
    <title></title>  
</head>
<body>
    <table>
        <tr>
            <th>数据库名称</th>
            <th>数据库类型</th>
            <th>mysql版本</th>
            <th>数据库规格</th>
            <th>备注</th>
            <th>数据库地址</th>
            <th>存储空间</th>
            <th>登记人</th>
        </tr>
        {% for item in data %}
            <tr>
                <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>
            </tr>
        {% endfor %}
    </table>
</body>
</html>


这个时候我们启动django来到浏览器里,在地址栏输入:外网地址:8000/lists/alionlinecs,就会看到之前的那个添加“阿里云线上服务器”的界面,如图:

技术分享


在点击了提交之后,就会看到地址栏里的add变成了lists,达到了我们的预期目标:

技术分享



在这篇文章的最后,我直接复制了http://blog.csdn.net/alex_chen_16/article/details/50850435 里对url处理请求的原理简述,留作备份和日后改进的参考。


1.      Django处理请求的方式

1) Django通过URLconf模块来进行判断。通常情况下,这就是ROOT_URLCONF配置的价值,但是如果请求携带了一个urlconf的属性(通常被中间件设置),那么这个被携带的urlconf将会替代ROOT_URLCONF的配置。

2) Django会调用Python模块并寻找各种urlpatterns。这是一个属于django.conf.urls.url()实例的python列表。

3) Django会遍历每个URL pattern,自上而下,并且选取收割匹配请求URL的pattern。

4) 一旦匹配某个url pattern的正则表达式,Django将导入并调用相关的view(这是一个简单的python函数,或者是一个class-based view)

这个view将会传递下列参数:

l  一个HttpRequest的实例

l  如果匹配了URL中一个no named group,那么参数将会按根据URL中的位置一一对应

l  如果匹配了URL中一个named group,且参数传递是通过named group来匹配的,那么参数将会被指定的kwargs代替。

5)  如果没有任何一个正则表达式被匹配,那么Django会抛出异常,并报错。


2. URL中的named  group

URL可以通过named group方式传递指定参数,语法为: (?P<name>pattern), name 可以理解为所要传递的参数的名称,pattern代表所要匹配的模式。例如,

  1. url(r‘^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$‘, views.month_archive),  

那么year,month将会对应views传递过来的year,month的值,而后面紧跟的则代表正则表达匹配的模式。


3. URL的反向解析
通常来说在处理完一个表单之后,网页会发生跳转。通常写URL我们都避免硬编码,这样不方便后期的调整。通常我们需要从URL获取两种内容,最主要是view能够通过URL获取一些标识并处理,另一些信息则是传递过来的参数。
Django提供了一种解决方案,URL mapper是与URL设计一一对应。你可以通过URLconf来实现,并反向使用它。例如:

  • 由用户通过浏览器发起URL请求,调用view,并将URL中的参数传递给view

  • 通过view并附上相应参数,找到相应匹配的URL。

后者我们称之为对URLs的反向解析。反向解析的例子,

  1. url(r‘^articles/([0-9]{4})/$‘, views.year_archive, name=‘news-year-archive‘),  


Django在不同的层次也提供了一些工具来实现URL的反向解析。

  • 在template中:使用url标签

  • 在python中:使用django.core.urlresolvers.reverse()函数

  • 在更高层次处理model实例时,可以使用get_absolute_url()方法

本文出自 “生活就是等待戈多” 博客,请务必保留此出处http://chenx1242.blog.51cto.com/10430133/1948971

以上是关于Django运维后台的搭建之三:用url去精细定制与反向解析的主要内容,如果未能解决你的问题,请参考以下文章

1-3.Win10系统利用Pycharm社区版安装Django搭建一个简单Python Web项目的步骤之三

如何对文件服务器进行精细化管理之三:存储报告

Django运维后台的搭建之五:引入databases和django-crispy-forms

运维工具SaltStack之三Grains组件

4Django实战第4天:xadmin快速搭建后台管理系统

django 配置管理后台,出现多个 admin/admin/admin