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>

浙公网安备 33010602011771号