Django

Django 自带的 admin 组件可以自定义配置,本文实现 Xadmin 对自定义显示数据列 (list_display) 的配置。

构建表单数据

模板层

从视图函数传来的数据变量是双层列表,第一层是数据库当中的每一条数据,第二层是每一条数据的各个字段值。

类似于

[
	["1","King","益达出版社",12],
	["2","Fight","西湖出版社",22],
]

所以在模板层通过双循环来取数据。


<tbody>
	{% for new_data in new_data_list %}
		<tr>
			{% for data in new_data %}
				<td>{{ data }}</td>
			{% endfor %}

		</tr>
	{% endfor %}
</tbody>

ModelXadmin 类

首先,设置一个列表变量 list_display 存储要显示数据表列信息。该变量不能再视图函数中设置,应该作为类的一个成员变量。该变量需要设置默认值 list_display = ["__str__", ] ,使在没有 Model 配置类的 model 中数据也能正常显示。

显示的列字段分为两种,一种是数据表自带的,一种是个人在配置类中设置的函数。

自带的列字段的处理

判断 list_display 中的元素是否为 str 类型,如果是代表为自带列字段,对每个数据对象用 getattr 函数获取相应的字段值。

# 取数据对象相应的字段
if isinstance(field, str):
	val = getattr(data_obj, field)

配置类中函数的处理

如果是函数,就执行该函数,添加的是该函数的返回值。

val = field(self, data_obj)

完整代码:

# 处理表单数据的列表
new_data_list = []

for data_obj in data_list:
	temp = []
	for field in self.list_display:
		# 取数据对象相应的字段
		if isinstance(field, str):
			val = getattr(data_obj, field)
		else:
			val = field(self, data_obj)
		temp.append(val)

	new_data_list.append(temp)

Model 配置类

在每个 app 下面的 Xadmin.py 文件中对数据表进行注册和配置。

list_play 变量

更改自己的 list_display 变量,将想显示的数据表中的字段加入进去。也可以加入函数字段。

函数作为列字段

当作为表单内容时,函数返回的是字符串,字符串可以是 HTML 标签。如果是 HTML 标签,则返回值需要经过 mark_safe 处理。

如果返回的是 a 标签,其中的 href 属性所用链接应当设置为相对路径,并且此处会用到 url 反向解析的内容。

def edit(self, obj=None):

	url = reverse('change', args=(obj.pk, ))
	return mark_safe('<a href="'+url+'">编辑</a>')

构建表头

模板层

传表头的数据时使用的是一维列表,即每个列字段的名称,所以只需要一个循环。

<thead>
<tr>
	{% for item in header_list %}
		<td>{{ item }}</td>
	{% endfor %}
</tr>
</thead>

ModelXadmin 类

为 list_display 的每个字段都添加相应的表头。分为三种情况,一是默认 list_display 列表,二是自定义的 list_display 列表,三是为函数列字段添加表头。

默认 list_display

若判断 list_display 中的元素为 __str__ 则认为是为默认的 list_display 添加表头,这里我们将 model_name 全部大写作为表头。

if isinstance(field, str):
	# 默认list_display
	if field == '__str__':
		val = self.model._meta.model_name.upper()

自定义 list_display

通过数据表类中的 meta 对象获取相应的字段值,若想显示中文,则应在数据表类中添加 verbose_name 属性。

 # 字段为数据表自带
if isinstance(field, str):
	# 默认list_display
	if field == '__str__':
		val = self.model._meta.model_name.upper()
	else:
		field_obj = self.model._meta.get_field(field)
		val = field_obj.verbose_name

函数列字段

传回作为表头的确认信息,由 Model 配置类进行处理。

# is_header判断是否在传表头时调用
	val = field(self, is_header=True)

完整添加表头代码:

# 处理表头
header_list = []

# 为list_display的每个字段都添加相应的表头
for field in self.list_display:

	# 字段为数据表自带
	if isinstance(field, str):
		# 默认list_display
		if field == '__str__':
			val = self.model._meta.model_name.upper()
		else:
			field_obj = self.model._meta.get_field(field)
			val = field_obj.verbose_name
	# 字段为自添加函数
	else:
		# is_header判断是否在传表头时调用
		val = field(self, is_header=True)
	header_list.append(val)

Model 配置类

别的地方不需要动,在判断传回的是表头时返回自定义表头。

# 用在传表头的时候
if is_header is True:
	return "操作"

完整 ModelXadmin 代码:

class ModelXadmin(object):
    # 存放要显示哪些字段的列表
    list_display = ["__str__", ]

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

    def list_view(self, request):
        # 所有的数据
        data_list = self.model.objects.all()
        # 数据表的名称
        model_name = self.model._meta.model_name

        # 处理表头
        header_list = []

        # 为list_display的每个字段都添加相应的表头
        for field in self.list_display:

            # 字段为数据表自带
            if isinstance(field, str):
                # 默认list_display
                if field == '__str__':
                    val = self.model._meta.model_name.upper()
                else:
                    field_obj = self.model._meta.get_field(field)
                    val = field_obj.verbose_name
            # 字段为自添加函数
            else:
                # is_header判断是否在传表头时调用
                val = field(self, is_header=True)
            header_list.append(val)

        # 处理表单数据的列表
        new_data_list = []

        for data_obj in data_list:
            temp = []
            for field in self.list_display:
                # 取数据对象相应的字段
                if isinstance(field, str):
                    val = getattr(data_obj, field)
                else:
                    val = field(self, data_obj)
                temp.append(val)

            new_data_list.append(temp)

        return render(request,
                      "list_view.html",
                      {
                          "data_list": data_list,
                          "model_name": model_name,
                          "new_data_list": new_data_list,
                          "header_list": header_list,
                      }
                      )

完整 Model 配置类 BookConfig 代码:

class BookConfig(ModelXadmin):

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

        # 用在传表头的时候
        if is_header is True:
            return "操作"

        url = reverse('change', args=(obj.pk, ))
        return mark_safe('<a href="'+url+'">编辑</a>')

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

        # 用在传表头的时候
        if is_header is True:
            return "操作"

        url = reverse('delete', args=(obj.pk,))
        return mark_safe('<a href="'+url+'">删除</a>')

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

        # 用在传表头的时候
        if is_header is True:
            return "操作"

        return mark_safe('<input type="checkbox">')

    list_display = [check, "nid", "title", "price", "publish", edit, delete]


完整模板代码:

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

<div class="container">
    <div class="row">
        <div class="col-md-9">
            <table class="table table-bordered table-striped">
                <thead>
                <tr>
                    {% for item in header_list %}
                        <td>{{ item }}</td>
                    {% endfor %}

                </tr>
                </thead>
                <tbody>
                {% for new_data in new_data_list %}
                    <tr>
                        {% for data in new_data %}
                            <td>{{ data }}</td>
                        {% endfor %}

                    </tr>
                {% endfor %}

                </tbody>
            </table>
        </div>
    </div>
</div>

完成效果

1540366987256

GitHub 地址:https://github.com/protea-ban/oldboy/tree/master/s9day84/Xadmindemo

原文地址:https://www.cnblogs.com/banshaohuan/p/9843861.html