这里要实现点击对应的表名称,显示具体表的详细内容,大致的流程是:
前端显示各个表名,如下:
<tbody>
{% for table_name,admin in app_tables.items %}
<tr class="border-bottom">
<td style="padding-bottom: 3px;padding-top: 3px;">
<a href="{% url 'table_objs' app_name table_name %}">{% render_app_name admin %}</a>
</td>
<td style="padding-bottom: 3px;padding-top: 3px;">Add</td>
<td style="padding-bottom: 3px;padding-top: 3px;">Change</td>
</tr>
{% endfor %}
</tbody>
主要就是:<a href="{% url 'table_objs' app_name table_name %}">{% render_app_name admin %}</a>,
对应表名的url被解析成/应用名/表名,如/plcrm/customer形式,对应的在路由项中有如下路由:path('<str:app_name>/<str:table_name>/',views.display_table_objs,name="table_objs"),请求处理的函数是views.display_table_objs:
def display_table_objs(req,app_name,table_name):
print("====>",app_name,table_name)
admin_class = mytestapp_admin.enable_admins[app_name][table_name]
print('-----.....>',admin_class,admin_class.model.__name__)
return render(req,"mytestapp/table_objs.html",{"admin_class":admin_class})
通过enable_admins字典获取到对应的admin_class,然后传递到前端,即table_objs.html,然后在全端展示各字段:
<!-- 表体中按照表头的字段,循环显示表中的数据 -->
<!-- 因为函数传递的是admin_class,而admin_class中有model属性,保存了对应的model类,感觉可以直接如下取数显示-->
{% for columndata in admin_class.model.objects.all %}
<tr>
<td>{{ columndata }}</td>
</tr>
{% endfor %}
上面的代码运行时会出现错误:
在网上查询,一般是这样解释的:出现这种错误是因为调用模型对象时使用了变量名,而不是对象名(模型类),也就是说必须使用对象名,如这里应该是Customer,但是后台传递过来的,即视图函数中带的数据就一个admin_class,这里就是CustomerAdmin,以通常的理解,CustomerAdmin中有model属相,这个属性的值是Customer,那就应该可以的,实际不行。
也就是说,在模板中使用models类取数时,必须使用类名称,不能使用变量名。所以,要使用Customer类来取对应表中的数据,但是视图函数要传递数据给模板,是用的字典,也就是模板使用的是key,无法使用类名,从而也就无法直接在模板中使用model类直接取数,需要在视图函数中查询出数据,传递给模板,或者在模板中使用自定义标签,来完成取数的功能。
第一种:修改视图函数,在视图函数中获取数据,然后传递给模板:
def display_table_objs(req,app_name,table_name):
admin_class = mytestapp_admin.enable_admins[app_name][table_name]
models_data = admin_class.model.objects.all()
return render(req,"mytestapp/table_objs.html",{"admin_class":admin_class,"model_class_name":admin_class.model.__name__,'model_data':models_data})
传给模板的model_data是查询出的数据QuerySet型数据,在模板中:
{% for kk in model_data %}
<tr>
<td>{{ kk.name }} | {{ kk.qq }}</td>
</tr>
{% endfor %}
因为前端显示的是admin_class中的list_display中定义的字段,所以,修改一下视图函数的中取数:models_data = admin_class.model.objects.values_list(*admin_class.list_display)
前端:
{% for kk in model_data %}
<tr>
{% for gg in kk %}
<td>{{ gg }} </td>
{% endfor %}
</tr>
{% endfor %}
第二种,使用自定义标签,也可以有两种处理方法
1、标签可以按照admin_class中的list_display取数,传递给前端,前端遍历生成html
@register.simple_tag
def get_query_sets_1(admin_class):
return admin_class.model.objects.values_list(*admin_class.list_display)
前端循环:
<tbody>
{% get_query_sets_1 admin_class as query_sets %}
{% for obj in query_sets %}
<tr>
{% for obj_item in obj %}
<td colspan="6">{{ obj_item }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
2、标签返回model中全部数据,再定义一个标签,按照list_display组装这些数据,生成一个html字符串,传递个前端。
@register.simple_tag
def get_query_sets_1(admin_class):
return admin_class.model.objects.all()
@register.simple_tag
def build_table_row(obj,admin_class):
row_ele = ""
for row_data in obj:
row_ele = row_ele +"<tr>"
for column in admin_class.list_display:
column_data = getattr(row_data,column)
row_ele += "<td colspan='6'>%s</td>"%column_data
row_ele = row_ele + "</tr>"
return mark_safe(row_ele)
前端:
<tbody>
{% get_query_sets_1 admin_class as query_sets %}
{% build_table_row query_sets admin_class %}
</tbody>
这种方法有一个问题,对于tags,使用getattr()取出的是plcrm.Tag.None,而使用第一种和视图函数返回,都是数值。
还有一个共同的问题,就是model类中有choices项的,对应的应该显示choices中的值,如source,这里都是显示数字,正常,显示说明文字,即对应的choices中的说明。
只能使用自定义标签方法的第二种:在组装标签时判断与替换
@register.simple_tag
def build_table_row(obj,admin_class):
row_ele = ""
print("===///:::",obj)
for row_data in obj:
row_ele = row_ele +"<tr>"
for column in admin_class.list_display:
field_obj = row_data._meta.get_field(column)
if field_obj.choices:
column_data = getattr(row_data,"get_%s_display"%column)()
else:
column_data = getattr(row_data,column)
row_ele += "<td colspan='6'>%s</td>"%column_data
row_ele = row_ele + "</tr>"
print(row_ele)
return mark_safe(row_ele)
显示如下:
source字段显示正确了,但是tags不正确,tags是manytomany的外键,修改一下:
@register.simple_tag
def build_table_row(obj,admin_class):
row_ele = ""
print("===///:::",obj)
for row_data in obj:
row_ele = row_ele +"<tr>"
for column in admin_class.list_display:
field_obj = row_data._meta.get_field(column)
if field_obj.choices:
column_data = getattr(row_data,"get_%s_display"%column)()
else:
column_data = getattr(row_data,column)
field_obj1 = getattr(row_data,column)
if hasattr(field_obj1,'values'):
s = ""
dic1 = field_obj1.values()[0]
print(type(dic1),dic1)
for v in dic1.values():
s = s + str(v) + ';'
column_data = s
row_ele += "<td colspan='6'>%s</td>"%column_data
row_ele = row_ele + "</tr>"
print(row_ele)
return mark_safe(row_ele)
对于外键,主要是判断字段是否有values方法(注意跟遍历字典时的values区别)。