无限分类作用不再赘述, 效果如下:

使用方法:
1, 将应用拷贝到项目目录下
2,在项目的setting文件中做两个设置
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'll' # 无限分类应用 limitless 缩写 增加此行 ] STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR,'ll/static') # 加载ll应用下的statics目录 增加这行 ]
3, 在项目的url文件中做如下配置
urlpatterns = [
path('admin/', admin.site.urls),
path('ll/',include("ll.urls"))
# 增加这行
]4, 根据ll的modles.py中的模型类sorts 到数据库生成表
python manage.py makemigrations ll #生成表对象
python manage.py migrate ll #生成数据库中表
5, 访问地址:
域名/ll/list
效果如访问的第一个文件所示
下载文件:
主要文件:
1, 无限分类递归查询
from .models import sorts
class sortAll:
sortList = []
level = 0
# 查询所有子类信息
@classmethod
def getChildren(cls, pid=0, space="", rs=[]):
if not rs:
rs = sorts.objects.filter(parentid=pid).order_by("orders")
del cls.sortList[:]
cls.level = 0
# 每次调用之前,清空列表
if rs:
for dic in rs:
if not cls.level:
cls.level = dic.level
# 将开始的父级水平定义为第一级
lev = dic.level #表中级别
if (lev == cls.level): #第一级
dic.space = ""
elif (lev == cls.level + 1):
space = " |---->"
dic.space = space
else:
dic.space = space
cls.sortList.append(dic)
pid = dic.id
rs = sorts.objects.filter(parentid=pid).order_by("orders")
if rs:
cls.getChildren(pid, " |" + space, rs)
return cls.sortList
@classmethod
# selectName : select 的name属性值
# pid : 父级id
# currentid : 当前默认选中类别
# top : 是否显示顶级类别
def selectTree(cls, pid=0, selectName="parentid", currentid=0, top=False):
lists = cls.getChildren(pid)
strs = '<select name="' + selectName + '">';
if top:
strs += '<option value="0">一级分类</option>'
for row in lists:
if (row.id == currentid):
strs += '<option value="' + str(row.id) + '" selected>' + row.space + row.title + '</option>'
else:
strs += '<option value="' + str(row.id) + '">' + row.space + row.title + '</option>'
strs += '</select>'
return strs
@classmethod
def getParentName(cls, sortpath="", fuhao="->"):
str = ""
if sortpath:
sortpath = sortpath[2:len(sortpath) - 1]
list = sortpath.split(",")
for index in range(len(list)):
row = sorts.objects.get(id=list[index])
if index == 0:
str += row.title
else:
str += fuhao + row.title
return str2, 基于django模型视图的增删改操作
from django.shortcuts import render
from django.http import HttpResponse
from .models import sorts
from .sortTree import sortAll
from django.db.models import F,Func,Value
from django.db.models.functions import Replace
def list(request):
list_child = sortAll.getChildren(0)
return render(request, "ll/list.html", {"list_children": list_child})
def add(request):
if request.method == "GET":
currentid = int(request.GET.get("parentid", 0))
dict = {"selectTree":sortAll.selectTree(0,"parentid",currentid,True)}
return render(request,"ll/add.html",dict)
elif request.method == "POST":
post = request.POST
parentid = post.get("parentid",0)
title = post.get("title")
ordders = post.get("orders")
if not title:
return HttpResponse("<script>alert('类别名称不能为空');history.back();</script>")
try:
result = sorts.objects.get(parentid=parentid, title=title)
if result:
return HttpResponse("<script>alert('类别已经存在');history.back();</script>")
except sorts.DoesNotExist:
pass
# 设置level, sortpath信息begin
level = 1
sortpath = "0,"
if parentid:
# 最顶级时使用默认设置值, 否则根据父级来决定
try:
row = sorts.objects.values("level", "sortpath").get(id=parentid)
level = row.get("level") + 1
sortpath = row.get("sortpath")
except sorts.DoesNotExist:
pass
data = {"title":title, "parentid":parentid, "level":level, "sortpath":sortpath, "orders":ordders}
obj = sorts.objects.create(**data)
sortpath = obj.sortpath + str(obj.id) + ","
sorts.objects.filter(id=obj.id).update(sortpath=sortpath)
return HttpResponse("<script>alert('添加成功');location.href='/ll/list/';</script>")
def edit(request):
if request.method == "GET":
id = request.GET.get("id", 0)
try:
row = sorts.objects.get(id=id)
except sorts.DoesNotExist:
return HttpResponse("<script>alert('传递参数不正确, 找不到数据');history.back();</script>")
else:
selectTree = sortAll.selectTree(pid=0, selectName='parentid', currentid=row.parentid, top=True)
return render(request, "ll/edit.html", {"row": row, "selectTree": selectTree})
elif request.method == "POST":
id = int(request.POST.get("id"))
parentid = int(request.POST.get("parentid"))
title = request.POST.get("title")
orders = request.POST.get("orders")
if not title:
return HttpResponse("<script>alert('名称不能为空');history.back();</script>")
# 判断同一个父类下不能有重复的名称
try:
rs = sorts.objects.exclude(id=id).get(parentid=parentid, title=title)
except sorts.DoesNotExist:
pass
else:
return HttpResponse("<script>alert('名称重复');history.back();</script>")
# 获取原来id的sorthpath及parentid
try:
row = sorts.objects.get(id=id)
except sorts.DoesNotExist:
return HttpResponse("<script>alert('id参数错误');history.back();</script>")
else:
oldParentid = row.parentid
oldSortPath = row.sortpath
oldLevel = row.level
# 获取现在id的父级的sorthpath
nowParentidSortPath = ""
if parentid:
try:
row1 = sorts.objects.values("sortpath", "level").get(id=parentid)
except sorts.DoesNotExist:
return HttpResponse("<script>alert('父类参数错误');history.back();</script>")
else:
nowParentidSortPath = row1.get("sortpath")
nowLevel = row1.get("level")
# 当前选择的父级id的sortpath
row.title = title
row.orders = orders
if parentid == oldParentid:
# 父类不变, 直接更新名称和排序就可以了
row.save()
elif oldSortPath in nowParentidSortPath:
# 判断修改类别父类不能为原类别的子类
return HttpResponse("<script>alert('不能选择自己或子级作为父类');history.back();</script>")
elif parentid == 0:
# 选择一级类别
level = 1
sortpath = "0," + str(id) + ","
row.level = level
row.sortpath = sortpath
row.parentid = 0
row.save()
chaLevel = oldLevel - level
# 更新所有子类的层级
# sorts.objects.exclude(id=id).filter(sortpath__icontains=oldSortPath).
# update(sortpath=Func(F('sortpath'), Value(oldSortPath), Value(sortpath), function='replace',),level = F("level") - chaLevel)
sorts.objects.exclude(id=id).filter(sortpath__icontains=oldSortPath).update(
sortpath=Replace('sortpath', Value(oldSortPath), Value(sortpath)),
level=F("level") - chaLevel
)
else:
sortpath = nowParentidSortPath + str(id) + ","
level = nowLevel + 1
chaLevel = oldLevel - level
row.sortpath = sortpath
row.level = level
row.parentid = parentid
row.save()
sorts.objects.exclude(id=id).filter(sortpath__icontains=oldSortPath).update(
sortpath=Replace('sortpath', Value(oldSortPath), Value(sortpath)),
level=F("level") - chaLevel
)
return HttpResponse("<script>alert('修改成功');location.href='/ll/list/';</script>")
def delete(request):
id = request.GET.get("id", 0)
sorts.objects.filter(sortpath__icontains=str(id) + ",").delete()
return HttpResponse("<script>alert('删除成功');location.href='/ll/list';</script>")4, 无限分类表Sorts模型
from django.db import models # 无限分类表 class sorts(models.Model): title = models.CharField(max_length=100) # 类别名称 parentid = models.IntegerField(default=0) # 类别的 父 id sortpath = models.CharField(default='',blank=True,max_length=200) # 从父级第一级开始,每层的id, 包含当前id level = models.SmallIntegerField(default=1) # 从父级第一级开始,为第几级 orders = models.IntegerField(default=1) # 同一级中的排序 pic = models.CharField(default='',blank=True,max_length=200)
