Xadmin组件构建之增删改查

settings.py

    'Xadmin.apps.XadminConfig',
    'app01.apps.App01Config',
    'app02.apps.App02Config',

Xadmin实现流程:

models.py

 1 启动:在Django执行的这一刻把每一个叫Xadmin.py文件都加载一遍 

#Xadmin/apps.py
from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules

class XadminConfig(AppConfig):
    name = 'Xadmin'

    def ready(self):   #当加载这个类的时候,这个方法自动执行
        autodiscover_modules('Xadmin')  #通过此步设置,Django一启动就是扫描每一个叫Xadmin.py的文件

2 创建一个单例对象:完成注册功能

Xadmin\service\Xadmin.py

# 定义每张表的配置类样式
class ModelXadmin(object):
    def __init__(self, model, site):

        self.model = model
        self.site = site  # site为单例对象

#定义一个全局类,用于创建单例对象,在这个类中完成了注册操作并设计了url
class XadminSite(object):

    def __init__(self, name='admin'):
        self._registry = {}

    def register(self, model, admin_class=None, **options):
        if not admin_class:
            admin_class = ModelXadmin  # 如果用户没有定制样式类,使用默认的样式类

        #site.register(Book,BookConfig)这句代码就相当于下面的注册
        self._registry[model] = admin_class(model, self) # {Book:BookConfig(Book,site)}
        #通过这一次注册就填加了一个键值对,键就是注册的模型表,值就是对应的定制样式类,后面跟了模型表的名字作为参数

site = XadminSite()  # 创建单例对象

模型表的简单注册:

from Xadmin.service.Xadmin import site,ModelXadmin
from app01.models import *

class BookConfig(ModelXadmin)
    pass

site.register(Book,BookConfig)
print("_registry:",site._registry)
#_registry: {<class 'app01.models.Book'>: <app01.Xadmin.BookConfig object at 0x04156D70>}

3 设计url

urls.py

from Xadmin.service.Xadmin import site

urlpatterns = [
    url(r'^Xadmin/', site.urls),
]

Xadmin\service\Xadmin.py

class XadminSite(object):

    # 一级分发
    def get_urls(self):
        print(self._registry)  # {Book:modelAdmin(Book),.......}注册过的模型表都存放在字典_registry中

        temp = []
        # 循环在Django一启动时就执行
        for model, admin_class_obj in self._registry.items():
            # 获取当前循环的model的字符串与所在app的字符串,为了拼接路径
            app_name = model._meta.app_label  # "app01"
            model_name = model._meta.model_name  # "book"

            #分发增删改查
            temp.append(url(r'^{0}/{1}/'.format(app_name, model_name), admin_class_obj.urls2), )

        return temp

    @property
    def urls(self):
        return self.get_urls(), None, None

    '''
    当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象。
    Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
    '''

    # 查看视图
    def list_view(self, request):
        return HttpResponse("list")

    # 增加视图
    def add_view(self):
        return HttpResponse("add")

    # 编辑视图
    def change_view(self, request, id):
        return HttpResponse("change")

    # 删除视图
    def delete_view(self, request, id):
        return HttpResponse("delete")

    # 二级分发
    def get_urls2(self):
        temp = []

        app_label = self.model._meta.app_label
        model_name = self.model._meta.model_name
        # 以上取app名称和model名称是为了给以下路径起别名(因为每一个app下的model名都是不一样的),用于反向解析
        temp.append(url(r"^$", self.list_view, name="%s_%s_list" % (app_label, model_name)))
        temp.append(url(r"^add/$", self.add_view, name="%s_%s_add" % (app_label, model_name)))
        temp.append(url(r"^(\d+)/change/$", self.change_view, name="%s_%s_change" % (app_label, model_name)))
        temp.append(url(r"^(\d+)/delete/$", self.delete_view, name="%s_%s_delete" % (app_label, model_name)))

        return temp

    @property
    def urls2(self):  
        return self.get_urls2(), None, None

上面这么做有一个问题,那就是我们访问book、userinfo以及其它表的增删改查页面是返回的都是同一个增删改查页面,这样做明显不符合逻辑,我们访问每张不同的表应该返回不同的增删改查页面,出现上面现象的原因是我们把二级分发的url以及增删改查的视图函数都定义到一个类(XadminSite)下了,我们最终使用的一直用都是这个类的单例对象site,只要我们调的是这里面的对象所有人用的配置信息都是一样的,

我们应该这样做,如果有定制的信息就用定制的,没有定制的信息就用默认的,

分析上面的代码有一个东西我们一直都没有用到,那就是admin_class_obj,这个代表的是每张表的配置类对象,这个样式类对象中有两个参数(model,site)。分析之后我们做如下修改:

from django.conf.urls import url
from django.shortcuts import HttpResponse, render, redirect
# 定义每张表的配置类样式
class ModelXadmin(object):
    def __init__(self, model, site):

        self.model = model
        self.site = site  # site为单例对象

    # 查看视图
    def list_view(self, request):
        return HttpResponse("list")

    # 增加视图
    def add_view(self):
        return HttpResponse("add")

    # 编辑视图
    def change_view(self, request, id):
        return HttpResponse("change")

    # 删除视图
    def delete_view(self, request, id):
        return HttpResponse("delete")

    # 二级分发
    def get_urls2(self):    (4)
        temp = []

        app_label = self.model._meta.app_label
        model_name = self.model._meta.model_name
        # 以上取app名称和model名称是为了给以下路径起别名(因为每一个app下的model名都是不一样的),用于反向解析
        temp.append(url(r"^$", self.list_view, name="%s_%s_list" % (app_label, model_name)))
        temp.append(url(r"^add/$", self.add_view, name="%s_%s_add" % (app_label, model_name)))
        temp.append(url(r"^(\d+)/change/$", self.change_view, name="%s_%s_change" % (app_label, model_name)))
        temp.append(url(r"^(\d+)/delete/$", self.delete_view, name="%s_%s_delete" % (app_label, model_name)))

        return temp

    @property
    def urls2(self):  # urls2跨类定义  (3)
        return self.get_urls2(), None, None

class XadminSite(object):

    # 一级分发
    def get_urls(self):  (2)
        print(self._registry)  # {Book:modelAdmin(Book),.......}注册过的模型表都存放在字典_registry中

        temp = []
        # 循环在Django一启动时就执行
        for model, admin_class_obj in self._registry.items():
            # 获取当前循环的model的字符串与所在app的字符串,为了拼接路径
            app_name = model._meta.app_label  # "app01"
            model_name = model._meta.model_name  # "book"

            #分发增删改查
            temp.append(url(r'^{0}/{1}/'.format(app_name, model_name), admin_class_obj.urls2),)
            #这时候不能用self.urls2,因为这个类中已经没有urls2方法了,我们想调的urls2在ModelXadmin类下面,
            # 可以通过admin_class_obj.urls2调到urls2

            '''
            url(r"app01/book",BookConfig(Book).urls2)

            '''
        return temp

    @property
    def urls(self):  (1)
        return self.get_urls(), None, None

当用户访问app01/book的时候,走的是BookConfig(Book).urls2,首先BookConfig(Book)实例化一个对象,先走BookConfig类中的__init__方法,发现没有,然后走它父类ModelXadmin中的__init__方法:

class ModelXadmin(object):
    def __init__(self, model, site):

        self.model = model
        self.site = site 

此时self.model就是Book

4 增删改查页面

(1) list_view

app01\Xadmin.py

#定义我们自己的样式
class BookConfig(ModelXadmin):
    list_display=["nid","title","publish","price","authors"] #定义查看页面有哪些字段
    list_display_links = ["title"]                 #定义点击哪个字段进入编辑页面

Xadmin\service\Xadmin.py

from django.conf.urls import url
from django.shortcuts import HttpResponse, render, redirect
from django.urls import reverse
from django.db.models import Q
from django.utils.safestring import mark_safe
from django.db.models.fields.related import ManyToManyField,ForeignKey

from Xadmin.utils.page import Pagination

# 构建表头数据和构建表单数据本应该放在ModelXadminl类下面list_view视图函数中,但数据太多放在里面会会显得杂乱
# 这里定义一个类专门用来在页面展示数据,把ModelXadminl类中的self以及list_view函数中的data_list和request三个参数传过来
class show_list(object):
    def __init__(self, config, data_list, request):
        self.config = config  # config代表传过来的self, self.config就是ModelXadminl类中的实例化对象self
        self.data_list = data_list
        self.request = request      
 def get_header(self):
        # 构建表头数据
        header_list = []
        print("header", self.config.new_list_display())  # [check,"nid","title","publish","price",edit,delete]

        for field in self.config.new_list_display():
            if isinstance(field, str):
                if field == "__str__":  # 说明是默认的样式,展示大写表名
                    val = self.config.model._meta.model_name.upper()
                else:
                    field_obj = self.config.model._meta.get_field(field)  # 获取表中字段对象
                    val = field_obj.verbose_name  # 获取字段中定义的名称

            else:  # 说明是定义的函数
                val = field(self.config, is_header=True)  # 获取表头,传is_header=True

            header_list.append(val)
        print(header_list)  # ["<input id='choice' type='checkbox'>", ' 编号', '书籍名称', 'publish', 'price', '操作', '操作']
        return header_list

    def get_body(self):
        # 构建表单数据
        new_data_list = []
        for obj in self.page_data:  # data_list:<QuerySet [<Book: 北京折叠>, <Book: 三体>]>
            temp = []
            for field in self.config.new_list_display():  # ["__str__"] [check,"nid","title","publish","price","authors",edit,delete]

                if isinstance(field, str):  # 判断字段是不是str类型
                    try:#为了捕捉__str__,防止报错
                        field_obj = self.config.model._meta.get_field(field) #拿模型表字段对象
                        # 判断是不是多对多字段(把authors取出来)
                        if isinstance(field_obj, ManyToManyField):
                            ret = getattr(obj, field).all()  #取出所有作者 :<QuerySet [<Author: xiaohei>, <Author: xiaobai>……]>
                            t=[]
                            for mobj in ret:  #千万记住多层循环的时候循环名称不要重复这里是obj和mobj
                                t.append(str(mobj))
                            val=",".join(t)
                        else:
                            if field_obj.choices:#如果当前字段对象有choices属性
                                #相当于把((1, '男'), (2, '女'))中的男或女拿出来
                                val = getattr(obj, "get_"+field+"_display")
                            else:
                                val = getattr(obj, field)  # 由字符串找对象的属性,相当于obj.field,也就是把'nid',title',''publish',price'拿出来了
                            if field in self.config.list_display_links:
                                # "app01/userinfo/(\d+)/change"
                                _url = self.config.get_change_url(obj)

                                val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
                    except Exception as e:  # 如果出错误说明是__str__
                        val = getattr(obj, field)

                else:
                    val = field(self.config, obj)  # 如果字段是函数,把当前处理的对象传给当前的函数(这一步为了拿到obj.pk,
                    # 然后拼接路径,比如我们在点击“编辑”的时候跳转到编辑界面,这里就用到了pk),执行后拿到返回结果

                temp.append(val)

            new_data_list.append(temp)

        '''
        new_data_list=[
            [check,1,北京折叠",苹果出版社,<a href=''>编辑</a>,<a href=''>删除</a>],
            [check,2,"三体", 苹果出版社,<a href=''>编辑</a>,<a href=''>删除</a>],
        ]
        '''
        return new_data_list

# 定义每张表的配置类样式
class ModelXadmin(object):
    list_display = ["__str__", ]  # 走默认的样式类的话默认显示"__str__"内容
    list_display_links = []  # 控制点哪个字段进入编辑界面,如果里面添加'publish'则点击publish就能进入编辑界面

    def __init__(self, model, site):

        self.model = model
        self.site = site  # site为单例对象

    # url路径反向解析
    def get_change_url(self, obj):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label

        _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,))

        return _url

    def get_delete_url(self, obj):
        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label

        _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,))

        return _url

    def get_add_url(self):

        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label

        _url = reverse("%s_%s_add" % (app_label, model_name))

        return _url

    def get_list_url(self):

        model_name = self.model._meta.model_name
        app_label = self.model._meta.app_label

        _url = reverse("%s_%s_list" % (app_label, model_name))

        return _url

    # 复选框、删除、编辑,定义在这里是为了在new_list_display函数中进行拼接
    # 在查看每一张表页面时都会出现这三项
    def check(self, obj=None, is_header=False):
        if is_header:
            return mark_safe("<input id='choice' type='checkbox'>")
        # 添加name='selected'_pk value='%s'是为批量操作actions做准备
        return mark_safe("<input class='choice_item' type='checkbox' name='selected_pk' value='%s'>"%obj.pk)

    def edit(self, obj=None, is_header=False):
        if is_header:
            return "操作"
        # 方案1:固定url
        # return mark_safe("<a href='/Xadmin/app01/book/%s/change/'>编辑</a>"%obj.pk)  #这样做把路径写死了

        # 方案2:拼接url
        # return mark_safe("<a href='%s/change/'>编辑</a>"%obj.pk) #比较safe方法,safe用在母版中的
        # %s前面没加/,当点击编辑的时候,按照当前页面的路径在后面把href里面的路径添加进去,这样做为了不把路径写死

        # 方案3:反向解析

        _url = self.get_change_url(obj) 

        return mark_safe("<a href='%s'>编辑</a>" % _url)

    def delete(self, obj=None, is_header=False):

        if is_header:
            return "操作"

        _url = self.get_delete_url(obj)

        return mark_safe("<a href='%s'>删除</a>" % _url)

    #扩展list_display列表,配置每个表默认都有复选框、删除、编辑三个操作,而且固定它们的位置
    def new_list_display(self):
        temp = []
        temp.append(ModelXadmin.check)  # append只能加一个元素
        temp.extend(self.list_display)  # extend扩展一个列表进来 ['nid','title','publish','price','authors']
     
        if not self.list_display_links:
            temp.append(ModelXadmin.edit)
        temp.append(ModelXadmin.delete)

        return temp

    # 查看视图
    def list_view(self, request):  # 这里注册用哪个样式类(默认、自定义),self就是谁
        print("self.model", self.model)  # 用户访问的是哪张表,self.model就是哪张表,这就是urls跨类定义最大的意义所在
        # 这里首先要弄清楚self是什么,我们一层一层的找,self->list_view->get_urls2->urls2->admin_class_obj,
        # 所以这里self就相当于admin_class_obj,这里就要搞清楚admin_class_obj是默认样式类的实例化对象还是自己定义样式类的实例化对象
        # 以访问Book表为例(这里Book表使用自定义的样式类,以下都是以访问Book表为例),
        # 上面打印内容为,self.model <class 'app01.models.Book'>
        model_name = self.model._meta.model_name  # 获取表名

        # 筛选获取当前表所有数据
        data_list = self.model.objects.all() # <QuerySet [<Book: 北京折叠>, …… ]>        

        # 按照showlist展示数据
        showlist = show_list(self, data_list, request)  # 实例化一个对象showlist,并传三个参数,其中self是当前ModelXadmin的实例化对象
        # 把self传给show_list类后,它里面的__init__进行接收(上面show_list函数用来接收self的参数是config)

        # 构建一个增加url路径
        add_url = self.get_add_url()
        return render(request, 'list_view.html', locals())  
                <table class="table table-bordered table-striped">
                    <thead>
                    <tr>
                        {% for item in showlist.get_header %}
                            <th>{{ item }}</th>
                        {% endfor %}
                    </tr>
                    </thead>
                    <tbody>
                    {% for data in showlist.get_body %}
                        <tr>
                            {% for item in data %}
                                <td>{{ item }}</td>
                            {% endfor %}
                        </tr>
                    {% endfor %}

                    </tbody>
                </table>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
    <script src="/static/jquery-3.3.1.js"></script>

    <style>
        .filter a {
            text-decoration: none;
        {# 去除a标签默认样式的下划线 #} color: grey;
        }

        .active {
            color: blue !important;
        }
    </style>
</head>
<body>

<h3>查看{{ model_name }}数据</h3>

<div class="container">
    <div class="row">
        <div class="col-lg-9">
            <!--添加数据-->
            <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
            <!--搜索数据开始-->
            {% if showlist.config.search_fields %}
                <form action="" class="pull-right">
                    <input type="text" name="q" value="{{ showlist.config.key_word }}">
                    <button>submit</button>
                </form>
            {% endif %}
            <!--搜索数据结束-->

            <!--添加form表单是为了在点击Go时确定发送数据的范围(不包括上面submit里面的内容)-->
            <form action="" method="post">
                {% csrf_token %}
                <!--action操作开始-->
                <select name="action" id="" style="width: 200px;padding: 5px 8px;display: inline-block">
                    <option value="">---------------</option>
                    {% for item in showlist.get_action_list %}
                        <option value="{{ item.name }}">{{ item.desc }}</option>
                    {% endfor %}
                </select>
                <button type="submit" class="btn btn-info">Go</button>
                <!--action操作结束-->

                <!--表格数据开始-->
                <table class="table table-bordered table-striped">
                    <thead>
                    <tr>
                        {% for item in showlist.get_header %}
                            <th>{{ item }}</th>
                        {% endfor %}
                    </tr>
                    </thead>
                    <tbody>
                    {% for data in showlist.get_body %}
                        <tr>
                            {% for item in data %}
                                <td>{{ item }}</td>
                            {% endfor %}
                        </tr>
                    {% endfor %}

                    </tbody>
                </table>
                <!--表格数据结束-->

                <!--分页开始-->
                <nav class="pull-right">
                    <ul class="pagination">
                        {{ showlist.pagination.page_html|safe }}
                    </ul>
                </nav>
                <!--分页结束-->
            </form>
        </div>

        <!--filter开始-->
        <div class="col-md-3">
            <!--如果list_filter有值说明是用户自定义的,展示除来-->
            {% if showlist.config.list_filter %}
                <div class="filter">
                    <h4 style="">Filter</h4>
                    {% for filter_field,linktags in showlist.get_filter_linktags.items %}
                        <div class="well">  <!-- class="well"为加面板-->
                            <p>By {{ filter_field.upper }}</p>
                            {% for link in linktags %}
                                <p>{{ link|safe }}</p>
                            {% endfor %}
                        </div>
                    {% endfor %}
                </div>
            {% endif %}

        </div>
        <!--filter结束-->
    </div>
</div>

<script>

    //给表头复选框加上点击事件(点击表头复选框,下面框全部选中,反之全部取消)
    $("#choice").click(function () {

        if ($(this).prop("checked")) {    //prop() 方法用于设置或返回被选元素的属性和值
            $(".choice_item").prop("checked", true)  //把所有的复选框都设置为选中
        } else {
            $(".choice_item").prop("checked", false)
        }

    })
</script>

</body>
</html>
list_view.html

(2) add_view

如何识别Form字段中一对多或者多对多字段

ModelForm组件

app01\Xadmin.py

from Xadmin.service.Xadmin import site,ModelXadmin
from django.forms import ModelForm
from django.forms import widgets as wid

#为book表定制modelform,用于添加页面
class BookModelForm(ModelForm):
    class Meta:
        model = Book
        fields = "__all__"

        labels={
            "title":"书籍名称",
            "price":"价格",
            "publishDate":"出版日期"
        }  #编辑页面展示效果,一对多、多对多字段不能在这里设置,可以在model表中通过verbose_name="",进行设置
        # widgets={  #应用这个然后页面就会显示样式,把浏览器的样式复制到母版中使用
        #     "title":wid.TextInput(attrs={"class":"form-control"})
        # }

#定义我们自己的样式
class BookConfig(ModelXadmin):
    modelform_class=BookModelForm                  #定义编辑页面使用我们自定义的

添加按钮

 <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
# 定义每张表的配置类样式
class ModelXadmin(object):
  
    modelform_class = []
 # 增加视图
    def add_view(self, request):
        model_name = self.model._meta.model_name  # 获取表名
        ModelFormDemo = self.get_modelform_class()  # 获取modelform类变量
        form = ModelFormDemo()  # 实例化一个对象form
     
        if request.method == "POST":
            form = ModelFormDemo(request.POST)
            if form.is_valid():
                obj=form.save() return redirect(self.get_list_url())

            #校验失败,返回当前失败的添加页面,为了让校验正确的数据不丢失
            return render(request,"add_view.html",locals())

        return render(request, 'add_view.html', locals())

    #用户访问哪张表我们不知道,用ModelForm做添加页面
  
获取modelform类: def get_modelform_class(self): # 如果用户没有定制,就使用默认配置的ModelFormDemo if not self.modelform_class: from django.forms import ModelForm from django.forms import widgets as wid class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo # 如果用户定制了自己的modelform就用用户自己的(app01/Xadmin.py) else: return self.modelform_class

添加页面和编辑界面差不多,让添加页面和编辑页面继承form

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
             <form action="" method="post" novalidate>
                {% csrf_token %}
                {% for field in form %}
                <div>
                    <label for="">{{ field.label }}</label>   <!--渲染每个标签的名字-->
                    {{ field }} <span class=" error pull-right">{{ field.errors.0 }}</span>
                </div>
                {% endfor %}

                 <button type="submit" class="btn btn-default pull-right">提交</button>
             </form>
        </div>
    </div>
</div>
form.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery-1.12.4.min.js"></script>


    <style>

          input,select {
            display: block;
            width: 100%;
            height: 34px;
            padding: 6px 12px;
            font-size: 14px;
            line-height: 1.42857143;
            color: #555;
            background-color: #fff;
            background-image: none;
            border: 1px solid #ccc;
            border-radius: 4px;
            -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
            -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
            transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
        }

        .error{
            color: red;
        }

    </style>
</head>
<body>


<h3>添加页面</h3>

{% include 'form.html' %}

</body>
</html>
add_view.html

(3) change_view

class ModelXadmin(object):
# 编辑视图
    def change_view(self, request, id):
        model_name = self.model._meta.model_name  # 获取表名
        ModelFormDemo = self.get_modelform_class()
        edit_obj = self.model.objects.filter(pk=id).first()  # 取出要编辑的对象

        if request.method == "POST":
            form = ModelFormDemo(request.POST, instance=edit_obj)  # 更新当前修改的数据
            if form.is_valid():
                form.save()
                return redirect(self.get_list_url())
            return render(request, 'add_view.html', locals())

        form = ModelFormDemo(instance=edit_obj)  # 传给instance,此时编辑页面就有值了
        return render(request, 'change_view.html', locals())
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery-1.12.4.min.js"></script>


    <style>

          input,select {
            display: block;
            width: 100%;
            height: 34px;
            padding: 6px 12px;
            font-size: 14px;
            line-height: 1.42857143;
            color: #555;
            background-color: #fff;
            background-image: none;
            border: 1px solid #ccc;
            border-radius: 4px;
            -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
            -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
            -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
            transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
        }

        .error{
            color: red;
        }

    </style>
</head>
<body>


<h3>编辑页面</h3>

{% include 'form.html' %}

</body>
</html>
change_view.html

(4) delete_view

点击删除后跳转到确认删除界面,点击取消跳转到查看界面,点击确认删除进行删除后跳转查看界面

class ModelXadmin(object):
    # 删除视图
    def delete_view(self, request, id):
        model_name = self.model._meta.model_name  # 获取表名
        url = self.get_list_url()
        if request.method == "POST":
            self.model.objects.filter(pk=id).delete()
            return redirect(self.get_list_url())

        return render(request, "delete_view.html", locals())

delete_view.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>删除{{ model_name }}数据</h3>
<form action="" method="post">
    {% csrf_token %}
    <button>确认删除?</button>
    <a href="{{ url }}">取消</a>
</form>

</body>
</html>

 

posted @ 2020-05-31 10:34  zh_小猿  阅读(211)  评论(0)    收藏  举报