Day 66 crm项目stark组件之表头数据展示,自定制

5、URL配置补充

反向解析,别名的使用

在设置url对应的视图函数时,我们可以给这个url添加一个别名,在使用时可以通过这个别名来反向生成url,这样即使url有修改,这样别名不变我们都不需要修改代码

增加别名时要注意,由于每个数据类我们都生成了增删改查4条url,所以在写别名时应该有些区别,不然会引起混淆,所以我们设计别名的格式为app名_表名_*


class ModelStark():
'''
默认配置类
'''

def __init__(self, model):
self.model = model
self.model_name = self.model._meta.model.name
self.app_label = self.model._meta.app_label

@property
def get_urls(self): temp = [ path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)), path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)), re_path("(\d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)), re_path("(\d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)), ] return temp, None, None
    
  def get_list_url(self):
  list_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
   return list_url

  def get_add_url(self):
  add_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
  return add_url

  def get_delete_url(self):
  delete_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
  return delete_url

 

6、列表展示页面

url设计完成后,我们就需要来设计每个url对应的页面了,我们注意到,其实不管是访问哪张表,增删改查都只对应相同的四个视图函数,那么应该如何区分我们访问的表呢

在样式类ModelStark中,我们定义了self.model,这里的model其实就是我们访问表的数据类,通过他我们就能拿到我们需要的数据显示到页面上,访问不同的表时这个model是不同的,这时就做到了访问什么表显示什么表的内容

list_display

在使用admin时,默认给我们展示的是一个个的类对象,当我们想要看到其它内容时,可以通过list_display属性设置

首先,这个属性应该是可以自定制的,如果用户没有定制,那么他应该有一个默认值,所以我们可以在ModelStark样式类中先自己定义一个list_display静态属性

class ModelStark(object):
    list_display = ("__str__",)  # 通过getattr(obj,"__str__")映射

    def __init__(self, model, site):
        self.model = model
        self.site = site

如果用户需要定制他,可以在app对应的stark.py文件中做如下配置

class BookConfig(ModelStark):
  list_display=["title","price","state","publish",show_authors]

这里我们写在list_display中的内容都是表中有的字段,其实里面还可以写我们自己定义的函数,用来将我们自己需要的内容显示到页面上,如上的show_authors

class BookConfig(ModelStark):

    def show_authors(self,obj=None,header=False):
        if header:
            return "作者信息"
        return " ".join([author.name for author in obj.authors.all()])

    list_display=["title","price","state","publish",show_authors]

 

添加编辑和删除按钮

from stark.service.sites import site, ModelStark
from .models import *
from django.utils.safestring import mark_safe


class BookConfig(ModelStark):

    def edit(self, obj=None, is_header=False):
        if is_header:
            return "操作"
        return mark_safe("<a href='/stark/app01/book/%s/change'>编辑</a>" % obj.pk)

    def delete(self, obj=None, is_header=False):
        if is_header:
            return "操作"
        return mark_safe("<a href='/stark/app01/book/%s/delete'>删除</a>" % obj.pk)
    list_display = ["id", "title", "price", edit, delete]
site.register(Book, BookConfig)


class AuthorConfig(ModelStark):
    list_display = ["name", "age"]
site.register(Author)

 

上面的内容可以看到我们返回的表头内容为操作

如果我们循环list_display得到的值是一个字符串,那么说明这应该是表中的一个字段,这时我们可以通过self.model._meta.get_field(字段名)的方法取到这个字段的对象,这个对象有一个verbose_name的属性,这个属性是用来描述一个字段的,在models中可以进行定义

class Book(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)
    price = models.DecimalField(verbose_name="价格", decimal_places=2, max_digits=5, default=12)

    def __str__(self):
        return self.title

上面的编辑和删除按钮就写死了,首先路径写死了,然后其他模型类里面没有,我们应该将其放在公共默认配置类里面,但是有个问题就是如果直接直接放在list_display 里面,用户自定义的list_display就会覆盖,没有默认的list_display

    def get_new_list_display(self):
        """
        添加共有的默认列
        :return:
        """
        temp = []
        temp.extend(self.list_display)  # 新建列表,添加list_display不管是默认还是用户自动义,
        temp.insert(0, ModelStark.show_checkbox)
        temp.append(ModelStark.show_edit_btn)
        temp.append(ModelStark.show_del_btn)

        return temp

接下来动态获取 编辑和删除按钮要跳转的路径:利用反向解析

 def get_list_url(self):
        """
         # 反向解析当前表的展示页面的URL
        :return:
        """
        list_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
        return list_url

    def get_add_url(self):
        """
         # 反向解析当前表的增加页面的URL
        :return:
        """
        add_url = reverse("%s_%s_add" % (self.app_label, self.model_name))
        return add_url

    def get_delete_url(self, obj):
        """
         # 反向解析当前表的删除页面的URL
        :return:
        """
        delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk, ))
        return delete_url

    def get_change_url(self, obj):
        """
         # 反向解析当前表的修改页面的URL
        :return:
        """
        change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk, ))
        return change_url
   @property
    def get_urls(self):
        temp = [
            path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)),
            path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)),
            re_path("(\d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)),
            re_path("(\d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)),
        ]
        return temp, None, None

 

设置默认的三列

    # 设置默认三个列
    def show_checkbox(self, obj=None, header=False):  # header 区分表头行和数据行
        """
        该函数设置复选框
        :param obj: 模型类对象
        :param header: 判断标志位
        :return: 一个标签
        """
        if header:
            return mark_safe("<input type='checkbox'>")  # 表头行
        return mark_safe("<input type='checkbox'>")  # 表数据行

    def show_del_btn(self, obj=None, header=False):
        """
        此函数为每一行定义一个删除按钮
        :param obj:
        :param header:
        :return:
        """
        if header:
            return "操作"
        return mark_safe("<a href='%s'>删除</a>" % self.get_delete_url(obj))   # 这里路径就不会写死了

    def show_edit_btn(self, obj=None, header=False):
        """
        此函数为每一行定义一个编辑按钮
        :param obj:
        :param header:
        :return:
        """
        if header:
            return "操作"
        return mark_safe("<a href='%s'>编辑</a>" % self.get_change_url(obj))

 

 表头数据

    def list_view(self, request):
        """
        展示页面
        :param request:
        :return:
        """
        queryset = self.model.objects.all()

        # 生成表头
        header_list = []
        for field_or_func in self.get_new_list_display():  # 这里拿到的 field 也是一个实例化类,拥有一些属性
            if callable(field_or_func):  # name = models.CharField(max_length=32)  例如name字段拥有man_length属性
                val = field_or_func(self, header=True)
                header_list.append(val)
            else:
                if field_or_func == "__str__":  # 这里表示用户没有自定制字段,默认返回对象的第一个字段
                    val = self.model_name.upper()  # 模型类名
                else:
                    field_obj = self.model._meta.get_field(field_or_func)
                    val = field_obj.verbose_name  # 字段对象有verboser_name属性
                header_list.append(val)

 

表数据

    def list_view(self, request):
        """
        展示页面
        :param request:
        :return:
        """
        queryset = self.model.objects.all()
        
        # 构建展示数据
        new_data = []
        for obj in queryset:
            temp = []

            for field_or_func in self.get_new_list_display():
                if callable(field_or_func):
                    val = field_or_func(self, obj)
                else:
                    try:
                        from django.db.models.fields.related import ManyToManyField
                        field_obj = self.model._meta.get_field(field_or_func)
                        # 判断是否多对多字段
                        if type(field_obj) == ManyToManyField:
                            raise Exception('list_display不能是多对多字段!')
                        # 判断字段是否有choices属性  choices=[(1, "已出版"), (2, "未出版社")],
                        if field_obj.choices:
                            val = getattr(obj, "get_%s_display" % field_or_func)()
                        else:
                            val = getattr(obj, field_or_func)

                    except Exception as e:
                        val = getattr(obj, field_or_func)()

                temp.append(val)
            new_data.append(temp)


        '''
        目标数据结构
        new_data=[
            ["python",123],
            ["java",234]
        ]
        '''

 

前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
</head>
<body>
<h3>查看数据</h3>


<div class="container">
    <div class="row">
        <table class="table table-striped table-hover">
            <thead>
            <tr>
                {% for item in header_list %}
                    <th>{{ item }}</th>
                {% endfor %}
            </tr>

            </thead>
            <tbody>
            {% for item in new_data %}
                <tr>
                    {% for info in item %}
                        <td>{{ info }}</td>
                    {% endfor %}
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
</div>
</body>
</html>

 

posted @ 2019-04-15 15:57  addit  Views(59)  Comments(0)    收藏  举报