利用Django通用类视图(class

发布时间:2019-09-25 08:13:39编辑:auto阅读(1541)

    最近在学习Django,官方文档介绍地十分详细。但是“大而全”就难免会有些不够速成,和我们这个浮躁的互联网时代格格不入,所以我就整理了这个文档。就像coolshell说的,一泡屎的时间就可以看完。


    框架的好处就是,它已经为用户处理了绝大多数的场景中的重复代码,提供了封装好的接口,使得我们在开发中十分方便。在web开发中,我们常常遇到的一个场景就是:页面发起一个请求,后端执行相应的处理(修改数据、查询数据、插入数据等操作),再予以返回。

    对于这些场景,Django提供了几个class-based view来处理:

    • ListView

    • UpdateView

    • CreateView

    • DeleteView

    这几个类视图分别对应着查询ListView、更新UpdateView、创建CreateView、删除DeleteView这几个操作。在整体上就可以分为查看、修改两个类型。下面,我们来通过一个例子来展现一下这几个View怎么使用。假设我们需要实现一个用于ssh验证的web服务。用户通过页面可以新建、查看、修改用于ssh登陆验证的内容(user、port、password、key)。

    Model

    既然是数据驱动的WEB,首先就必须要有数据。
    针对于我们的需求,数据库设计如下:

    class SSHAuth(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=50, unique=True)
        password = models.CharField(max_length=50, blank=True)
        privateKey = models.FileField(upload_to='sshKey', blank=True)
        user = models.CharField(max_length=30, blank=True)
        port = models.IntegerField(blank=True)
    
        # python3用__str__
        def __unicode__(self):
            return u'%s' % self.name

    这里涉及到文件上传,想要了解可以参考我的另一篇整理文档

    查询视图

    ListView

    对应官网文档
    首先,从最简单的展示开始。ListView可以通过你给出的model以及想要展示的model中的field,在对应的数据库中查询出对应的对象存放在List对象中,并传递给template渲染。这个view只实现了get方法,它只接受get请求。也符合它用于查看数据的需求。在代码中,我们只需要指定它对应的模板,对应的model就可以了。

    view

    from django.views.generic.edit import CreateView
    
    
    class SSHAuthListView(ListView):
    
        template_name = 'app_name/sshauth_list.html'
        model = SSHAuth

    说明:
    上面我没有给出filed的值,默认就是SSHAuth这个model中的所有filed都将被展示。
    其实template_name也可以不特别给出。如果你在Django设置settings.py中的TEMPLATES下配置了'APP_DIRS': True 的话,Django默认会去渲染/project/app_name/templates/app_name/sshauth_list.html这个文件。

    url

    from django.conf.urls import patterns, url
    from .view import SSHAuthListView
    urlpatterns = patterns('',
        url(r'^sshAuth/$', SSHAuthListView.as_view(), name='listSSHAuth'),

    template

    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Password</th>
                <th>PrivateKey</th>
                <th>User</th>
                <th>Port</th>
            </tr>
        </thead>
        <tbody>
        {% for item in object_list %}
            <tr>
                <td>{{ item.id }}</td>
                <td>{{ item.name }}</td>
                <td>{{ item.password }}</td>
                <td>{{ item.privateKey }}</td>
                <td>{{ item.user }}</td>
                <td>{{ item.port }}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

    说明:
    模板中的object_list对象就是view从model中取出的数据。以list的类型存储着所有数据instance。这个'object_list'的变量名是Django默认提供的,也可以人为修改为你想要的变量名,详细请看官网文档。


    修改视图

    接下来就是第二类修改视图了。在web开发中约定俗成的规则是,对于查询类的请求用get,对于修改类的请求用post。Django在设计的时候也遵循了这个原则,所以以下的每个view中,都具有支持get和post的函数。

    CreateVIew:

    • get——根据model提供一个空form

    • post——接收从get发来的请求,数据合法性校验,插入数据库

    UpdateView:

    • get——根据model从数据库取出实例,并渲染form

    • post——接收从get来的请求,数据合法性校验,并更新数据库

    CreateView

    对应官网文档

    view

    class SSHAuthCreateView(CreateView):
    
        template_name = 'app_name/ssh_create.html'
        model = SSHAuth
        success_url = reverse_lazy('app_name:listSSHAuth')

    说明:
    model就是对应的数据库,在get请求发送过来的时候,Django会根据model里的字段个数、类型渲染form。而在post请求发送过来的时候,Django会根据model里的field属性去做合法性校验(类型是否正确、字段是否必填等),在校验成功以后重定向至success_url。

    像上面的SSHAuthCreateView直接取model里面的数据,在password输入的时候input的type默认取的是text(因为model为CharField)。但是我们想要它是一个password的type。或者你想给它加入class属性,用于指定css。这样的话,就要自定制form。可以自己写一个form_class,然后在CreateView里面添加这个form_class。

    form

    from django import forms
    from .models import SSHAuth, Inventory
    
    
    bootstrap_form_css_class = {"class": 'form-control'}
    
    class SSHAuthBootstrapForm(forms.ModelForm):
        """
        Use Bootstrap css.
        An abstract base class.
        """
        class Meta:
            model = SSHAuth
            fields = ['name', 'password', 'privateKey', 'user', 'port']
            # add html class attribute to form's component.
            widgets = {
                'name': forms.TextInput(attrs=bootstrap_form_css_class),
                'password': forms.PasswordInput(attrs=bootstrap_form_css_class),
                'privateKey': forms.ClearableFileInput(attrs=bootstrap_form_css_class),    
                #ClearableFileInput提供对UpdateView的clear支持
                'user': forms.TextInput(attrs=bootstrap_form_css_class),
                'port': forms.TextInput(attrs=bootstrap_form_css_class),
            }

    说明:
    fields字段为想要展示的字段,因为id是自增的主键,所以不做修改。widgets为form的字段类型以及html属性。其中的PasswordInput会将form中的该字段设为password类型;而ClearableFileInput则是带有清除文件功能的类型。

    这样,只需要在view当中加入这个form_class就可以实现模板中渲染的form表单具有自定义的属性了:

    class SSHAuthCreateView(CreateView):
    
        template_name = 'app_name/ssh_create.html'
        form_class = SSHAuthBootstrapForm
        success_url = reverse_lazy('app_name:listSSHAuth')

    url

    url(r'^sshAuth/createItem/$', SSHAuthCreateView.as_view(), name='createSSHAuth'),

    template

    <form role="form" method="post" enctype="multipart/form-data" action="{% url 'app_name:createSSHAuth' %}">
        {% csrf_token %}
        {% for field in form %}
            {% if field.errors %}
                <div class="form-group has-error" >
            {% else %}
                <div class="form-group">
            {% endif %}
                {{ field.label_tag }}
                {{ field }}
            {% for error in field.errors %}
                <span class="label label-danger">{{ error }}</span>
            {% endfor %}
                </div>
        {% endfor %}
            <button type="submit" class="btn btn-primary">{% block btn_name %}{% endblock %}</button>
    </form>

    html

    生成的html代码如下:

    <form role="form" method="post" enctype="multipart/form-data" action="/app_name/createItem">
                <input type='hidden' name='csrfmiddlewaretoken' value='*****' />
                
                
                <div class="form-group">
                
                    <label for="id_name">Name:</label>
                    <input class="form-control" id="id_name" maxlength="50" name="name" type="text" />
                    
                </div>
                
                
                <div class="form-group">
                
                    <label for="id_password">Password:</label>
                    <input class="form-control" id="id_password" maxlength="50" name="password" type="text" />
                    
                </div>
                
                
                <div class="form-group">
                
                    <label for="id_privateKey">PrivateKey:</label>
                    <input class="form-control" id="id_privateKey" name="privateKey" type="file" />
                    
                </div>
                
                
                <div class="form-group">
                
                    <label for="id_user">User:</label>
                    <input class="form-control" id="id_user" maxlength="30" name="user" type="text" />
                    
                </div>
                
                
                <div class="form-group">
                
                    <label for="id_port">Port:</label>
                    <input class="form-control" id="id_port" name="port" type="text" />
                    
                </div>
                
                <button type="submit" class="btn btn-primary">Create</button>
            </form>

    在渲染的时候,Django已经自动根据model、form_class自动处理了form的所有字段。包括type name id maxlength等属性。


    剩下的UpdateView以及DeleteView与CreateView的实现也是相类似的原理。需要注意的就是在view代码中,即使是指定了form_class字段,而且form_class中也有指定model,但是还是需要在view代码里给出model。具体实现不再赘述。

关键字