个人学习开发一个django web端程序,基础不扎实期望解决以下问题:
将数据库中读取的菜单结构,生成前端jsTree所需的json格式
表结构如下,目前设计的最深4级:
menu_id: 使用此ID进行同级排序,用于左侧菜单树的顺序展示
menu_name:菜单树显示名称
menu_parent_id:该节点的上级ID,ID用的数据库默认主键,非menu_id,因为menu_id可能会因为调整顺序而变更
期望输出返回前端的JSON格式:
[
{
"id": "1",
"text": "安全功能三级",
"children": [
{
"id": "1.1",
"text": "子节点 1.1",
"children": [
{ "id": "1.1.1", "text": "叶子节点 1.1.1" },
{ "id": "1.1.2", "text": "叶子节点 1.1.2" }
]
},
{ "id": "1.2", "text": "子节点 1.2" }
]
},
{
"id": "2",
"text": "节点 2",
"children": [
{ "id": "2.1", "text": "子节点 2.1" },
{ "id": "2.2", "text": "子节点 2.2" }
]
}
]
以下是一些Django环境信息:
数据库表models信息:
class casetree(models.Model):
menu_id = models.IntegerField(verbose_name='菜单ID')
menu_name = models.CharField(verbose_name='菜单名称',max_length=32)
menu_parent_id = models.IntegerField(verbose_name='上级ID')
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (23,'一级菜单A',0);
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (24,'一级菜单B',0);
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (25,'一级菜单C',0);
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (26,'二级菜单AA',12);
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (27,'二级菜单AB',12);
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (28,'三级菜单AAA',18);
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (29,'四级菜单AAAA',20);
insert into case_casetree (menu_id,menu_name,menu_parent_id) values (30,'四级菜单AAAB',20);
期望可以得到代码片段或解决的具体思路,自己研究了下递归没鼓捣出来
引用chatgpt部分指引作答:
你可以使用递归的方式来生成所需的JSON格式。首先,你需要查询数据库获取所有的菜单数据,并以某种方式对其进行排序,确保同级菜单按照menu_id的顺序展示。然后,你可以定义一个递归函数,该函数接收当前菜单节点的ID作为参数,并返回该节点及其子节点的JSON表示。
下面是一个示例代码片段,展示了如何实现这个逻辑:
def generate_menu_json(menu_id):
menu_data = casetree.objects.filter(menu_parent_id=menu_id).order_by('menu_id')
menu_json = []
for menu in menu_data:
menu_item = {
'id': str(menu.menu_id),
'text': menu.menu_name,
}
children = generate_menu_json(menu.menu_id)
if children:
menu_item['children'] = children
menu_json.append(menu_item)
return menu_json
# 在视图或其他地方调用递归函数,并将生成的JSON数据返回给前端
def get_menu_json(request):
root_menu_id = 0 # 假设根节点的menu_id为0
menu_json = generate_menu_json(root_menu_id)
return JsonResponse(menu_json, safe=False)
这个例子中,首先从数据库中获取指定menu_id的所有子菜单,并按照menu_id排序。然后,对每个菜单项进行处理,创建一个字典表示该菜单节点,包含'id'和'text'属性。接下来,递归调用generate_menu_json函数来获取当前菜单节点的子节点,并将其作为'children'属性添加到菜单项字典中。最后,将菜单项字典添加到menu_json列表中。
最后,你可以将生成的menu_json作为JSON数据返回给前端。这里使用JsonResponse来生成JSON响应。
请注意,上述代码是基于你提供的表结构和数据示例进行的,并假设根节点的menu_id为0。你可能需要根据实际情况对代码进行适当的调整。另外,确保在Django的视图中导入必要的模块,如JsonResponse和你的casetree模型。
from django.http import JsonResponse
from .models import Menu
def get_menu(menu_id):
menu = Menu.objects.get(menu_id=menu_id)
menu_data = {
'menu_id': menu.menu_id,
'menu_name': menu.menu_name,
'sort_order': menu.sort_order,
'children': []
}
child_menus = Menu.objects.filter(parent_id=menu_id).order_by('sort_order')
for child_menu in child_menus:
menu_data['children'].append(get_menu(child_menu.menu_id))
return menu_data
def menu_data(request):
top_menus = Menu.objects.filter(parent_id=0).order_by('sort_order')
menu_data = []
for top_menu in top_menus:
menu_data.append(get_menu(top_menu.menu_id))
return JsonResponse(menu_data, safe=False)
在上述代码中,我们首先定义了一个递归函数get_menu,该函数接收一个菜单ID作为参数。函数根据菜单ID获取菜单对象,并构建一个菜单字典。然后,它查找该菜单的子菜单,并对每个子菜单调用递归函数,将子菜单添加到父菜单的children字段中。
在menu_data视图函数中,我们首先获取顶级菜单(父菜单ID为0的菜单),然后对每个顶级菜单调用get_menu函数,得到包含层级结构的菜单数据列表。最后,我们使用JsonResponse返回菜单数据。
请注意,在调用JsonResponse时,我们将safe参数设置为False,以允许返回的JSON对象是一个列表。
这样修改后,递归函数会根据父菜单ID来确定哪个菜单的子菜单,并以层级结构的方式输出所有菜单数据。
def category_data(request):
category = CategoryData.objects.all() // 数据库数据
category_info = serializers.serialize('json', category) // 将数据转为json格式
category_info = json.loads(category_info)
category_info_data = []
for i in range(len(category_info)):
category_info_data.append(category_info[i]['fields'])
lists = []
tree = {}
pid = ''
for i in category_info_data:
item = i
tree[item['cat_id']] = item
root = None
for i in category_info_data:
obj = i
if not obj['pid']:
root = tree[obj['cat_id']]
lists.append(root)
else:
pid = obj['pid']
if 'childList' not in tree[pid]:
tree[pid]['childList'] = []
tree[pid]['childList'].append(tree[obj['cat_id']])
data = {
'data': {
'category_data': lists
},
'code': 200,
'msg': 'true'
}
return JsonResponse(data, safe=False)
不知道你这个问题是否已经解决, 如果还没有解决的话:解决方案:
首先需要定义一个递归函数来获取菜单树。
如果有子节点,就遍历子节点,将子节点作为该节点的子节点,不断递归下去,直至获取到所有的节点。
下面是获取菜单树的函数代码:
from django.core import serializers
from django.http import JsonResponse
def get_menu_tree(menu_list, parent_id=None):
result = []
for menu in menu_list:
if menu['menu_parent_id'] == parent_id:
children = get_menu_tree(menu_list, menu['menu_id'])
menu_dict = {
'id': menu['menu_id'],
'text': menu['menu_name'],
'children': children
}
result.append(menu_dict)
return result
接下来是将菜单树转换为jsTree需要的JSON格式。
在view中获取数据库中的菜单数据并调用get_menu_tree函数,然后将结果转换为JSON格式。
最后将JSON数据返回到前端即可。
下面是将菜单树转换为jsTree格式的代码:
def menu_tree(request):
menu_list = list(Menu.objects.order_by('menu_id').values('menu_id', 'menu_name', 'menu_parent_id'))
menu_tree = get_menu_tree(menu_list)
menu_json = serializers.serialize('json', menu_tree)
return JsonResponse(menu_json, safe=False)
在前端中调用该接口获取JSON数据,并将数据转换为jsTree格式后,即可完成菜单的呈现。
希望以上解决方案能够帮到你。
直接按parent_id分组查询