2026-08-02 14:07:04 +08:00
|
|
|
|
"""注释"""
|
|
|
|
|
|
from django.db import models
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
输入 :当前用户实例(self)
|
|
|
|
|
|
输出 :包含所有下级用户的 扁平化列表 (多级结构被展开)
|
|
|
|
|
|
递归逻辑 :
|
|
|
|
|
|
先获取当前用户的直接下级(通过 self.subordinates.all())
|
|
|
|
|
|
对每个下级用户 递归调用自身,继续向下查找
|
|
|
|
|
|
合并所有结果到一个列表中
|
|
|
|
|
|
用户A
|
|
|
|
|
|
├─ 用户B
|
|
|
|
|
|
│ ├─ 用户C
|
|
|
|
|
|
│ └─ 用户D
|
|
|
|
|
|
└─ 用户E
|
|
|
|
|
|
|
|
|
|
|
|
[用户B, 用户C, 用户D, 用户E] # 按深度优先顺序
|
|
|
|
|
|
语法: wei = weiuser.objects.get(unionid="元宝零售")
|
|
|
|
|
|
print( wei.get_all_subordinates( ) )
|
|
|
|
|
|
结果: [<weiuser: weiuser object (oy4Jw6A1T3WkKOOhMxcbQTDSM8rs)>]
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
defautl_img = (
|
|
|
|
|
|
"https://oss.fujugongxiang.com/six/%E7%A6%8F%E8%81%9A%E8%B4%A1%E7%BF%94%E5%B0%8F%E7%A8%8B%E5%BA%8F/home%E9%A1%B5%E9%9D%A2%E4%B8%BB%E5"
|
|
|
|
|
|
"%9B%BE/%E5%A4%B4%E5%83%8F.png")
|
|
|
|
|
|
|
|
|
|
|
|
from django.utils.translation import gettext_lazy
|
|
|
|
|
|
|
|
|
|
|
|
models_app_name = "django_app"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class weiuser用户角色表choicesStatus(models.TextChoices):
|
|
|
|
|
|
"""商家转账订单状态"""
|
|
|
|
|
|
推广员 = "推广员", gettext_lazy("推广员")
|
|
|
|
|
|
企微员工 = "企微员工", gettext_lazy("企微员工")
|
|
|
|
|
|
无状态 = "无状态", gettext_lazy("无状态")
|
|
|
|
|
|
普通会员 = "普通会员", gettext_lazy("普通会员")
|
|
|
|
|
|
六果科技有限公司 = "六果科技有限公司", gettext_lazy("六果科技有限公司")
|
|
|
|
|
|
群好友 = "群好友", gettext_lazy("群好友")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class weiuser(models.Model):
|
|
|
|
|
|
"""用户基础信息表"""
|
|
|
|
|
|
objects = models.Manager() #
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
class ChoicesStatus(models.TextChoices):
|
|
|
|
|
|
"""商家转账订单状态"""
|
|
|
|
|
|
推广员 = "推广员", gettext_lazy("推广员")
|
|
|
|
|
|
企微员工 = "企微员工", gettext_lazy("企微员工")
|
|
|
|
|
|
无状态 = "无状态", gettext_lazy("无状态")
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
unionid = models.CharField(primary_key=True, max_length=120)
|
|
|
|
|
|
user_角色权限 = models.CharField(choices=weiuser用户角色表choicesStatus, default=weiuser用户角色表choicesStatus.普通会员)
|
|
|
|
|
|
user_企微角色权限 = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
mini_openid = models.CharField(max_length=100, db_comment="自身id", null=True, blank=True, unique=True)
|
|
|
|
|
|
wechat_openid = models.CharField(max_length=100, db_comment="服务号自身id", null=True, blank=True, unique=True)
|
|
|
|
|
|
wecom_openid = models.CharField(max_length=100, db_comment="企微自身id", null=True, blank=True, unique=True)
|
|
|
|
|
|
external_userid = models.CharField(max_length=100, db_comment="外部联系人ID", null=True, blank=True, )
|
|
|
|
|
|
uesr_手机号码 = models.CharField(null=True, blank=True, )
|
|
|
|
|
|
user_昵称 = models.CharField(max_length=120, db_comment="用户的昵称", default="匿名用户")
|
|
|
|
|
|
user_头像 = models.CharField(max_length=245, db_comment="用户头像",
|
|
|
|
|
|
default="https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png")
|
|
|
|
|
|
user_用户当前的等级 = models.IntegerField(default=1, ) # 自身的等级
|
|
|
|
|
|
user_省份 = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
user_城市 = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
user_区县 = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
user_街道信息 = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
user_绑定企微usrID账号 = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
user_绑定企微UNIONID = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
user_IP地址 = models.GenericIPAddressField(null=True, blank=True, )
|
2026-08-21 23:48:29 +08:00
|
|
|
|
user_手机设备参数 = models.JSONField(null=True, blank=True, )
|
2026-08-02 14:07:04 +08:00
|
|
|
|
user_绑定用工关系 = models.CharField(max_length=128, null=True, blank=True, )
|
|
|
|
|
|
codeConfigId = models.TextField(blank=True, null=True, ) # 企微的标签ID
|
|
|
|
|
|
codeQrCode = models.TextField(blank=True, null=True, ) # 企微的二维码
|
|
|
|
|
|
codeRemark = models.TextField(blank=True, null=True, ) # 企微备注的信息
|
|
|
|
|
|
parent = models.ForeignKey(to="self", on_delete=models.SET_NULL, related_name="children", null=True,
|
|
|
|
|
|
blank=True, ) # 模式:保护模式,有数据话是不能删除的;
|
|
|
|
|
|
add_time = models.DateTimeField(null=True, blank=True, db_comment="用户添加好友的时间")
|
|
|
|
|
|
dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间
|
|
|
|
|
|
updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() )
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
class Meta:
|
|
|
|
|
|
db_table = "weiuser" # 给数据表自定义一个名称;默认的会是在 应用名+类名
|
|
|
|
|
|
app_label = models_app_name
|
|
|
|
|
|
ordering = ["-dateAndTime", "-updateTime"]
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
def get_all_subordinates(self):
|
|
|
|
|
|
"""递归获取所有下级(包括间接下级)"""
|
|
|
|
|
|
subs = []
|
|
|
|
|
|
for sub in self.children.all():
|
|
|
|
|
|
subs.append(sub)
|
|
|
|
|
|
subs.extend(sub.get_all_subordinates())
|
|
|
|
|
|
return subs
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# ↓↓↓ 新增方法:获取所有上级(递归实现)↓↓↓
|
|
|
|
|
|
def get_all_superiors(self):
|
|
|
|
|
|
"""
|
|
|
|
|
|
返回列表格式:[直接上级, 上上级, 上上上级...]
|
|
|
|
|
|
"""
|
|
|
|
|
|
superiors = []
|
|
|
|
|
|
# 递归终止条件:没有上级时停止
|
|
|
|
|
|
if self.parent:
|
|
|
|
|
|
superiors.append(self.parent)
|
|
|
|
|
|
# 递归获取上级的上级
|
|
|
|
|
|
superiors.extend(self.parent.get_all_superiors())
|
|
|
|
|
|
return superiors
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
def get_nth_level_superior(self, n):
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取第n级上级
|
|
|
|
|
|
:param n: 上级层级 (1=直接上级, 2=上上级, 以此类推)
|
|
|
|
|
|
:return: Weiuser对象或None
|
|
|
|
|
|
"""
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取当前用户往上 n 级的父元素
|
|
|
|
|
|
:param n: 要查询的上级层级数 (必须 >=1)
|
|
|
|
|
|
:return: weiuser 对象或 None (如果不存在)
|
|
|
|
|
|
"""
|
|
|
|
|
|
if n < 1:
|
|
|
|
|
|
raise ValueError("n 必须大于或等于 1")
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
current = self
|
|
|
|
|
|
# 循环向上查询 n 次
|
|
|
|
|
|
for _ in range(n):
|
|
|
|
|
|
if not current.parent:
|
|
|
|
|
|
return None # 没有父级时提前终止
|
|
|
|
|
|
current = current.parent
|
|
|
|
|
|
return current
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
"""
|
|
|
|
|
|
这种实现方式更加简洁,但需要注意:
|
|
|
|
|
|
它使用了链式递归调用,可能会增加递归深度
|
|
|
|
|
|
每次递归都会重新检查字段是否存在,虽然安全但效率稍低
|
|
|
|
|
|
性能考虑
|
|
|
|
|
|
对于树形结构操作,递归实现通常更简洁,但在实际应用中需要注意:
|
|
|
|
|
|
Python递归深度限制:默认1000层,可通过sys.setrecursionlimit()调整
|
|
|
|
|
|
性能开销:递归调用比循环有更高的开销
|
|
|
|
|
|
内存使用:递归会占用更多栈空间
|
|
|
|
|
|
在大多数实际应用中,树结构的深度不会超过100层,因此递归实现通常是可行的。但如果预期树结构会非常深(如超过1000层),建议使用循环实现或混合实现。
|
|
|
|
|
|
"""
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
def find_ancestor_by_field(self, field_name, target_value, include_self=False):
|
|
|
|
|
|
"""
|
|
|
|
|
|
从当前用户向上查找,找到第一个指定字段等于目标值的祖先
|
|
|
|
|
|
:param field_name: 要查找的字段名
|
|
|
|
|
|
:param target_value: 目标值
|
|
|
|
|
|
:param include_self: 是否包含自身
|
|
|
|
|
|
:return: Weiuser对象或None
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 验证字段名是否有效 - 修复方法
|
|
|
|
|
|
if not hasattr(self, field_name):
|
|
|
|
|
|
raise ValueError(f"无效字段名: {field_name}")
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# 如果包含自身且满足条件,直接返回
|
|
|
|
|
|
if include_self and getattr(self, field_name) == target_value:
|
|
|
|
|
|
return self
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# 向上遍历祖先
|
|
|
|
|
|
current = self.parent
|
|
|
|
|
|
while current:
|
|
|
|
|
|
if getattr(current, field_name) == target_value:
|
|
|
|
|
|
return current
|
|
|
|
|
|
current = current.parent
|
|
|
|
|
|
return None
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
def find查找指定的上级(self, field_name, target_value, include_self=False):
|
|
|
|
|
|
"""
|
|
|
|
|
|
从当前用户向上查找,找到第一个指定字段等于目标值的祖先
|
|
|
|
|
|
:param field_name: 要查找的字段名
|
|
|
|
|
|
:param target_value: 目标值
|
|
|
|
|
|
:param include_self: 是否包含自身
|
|
|
|
|
|
:return: Weiuser对象或None
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 验证字段名是否有效 - 修复方法
|
|
|
|
|
|
if not hasattr(self, field_name):
|
|
|
|
|
|
raise ValueError(f"无效字段名: {field_name}")
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# 如果包含自身且满足条件,直接返回
|
|
|
|
|
|
if include_self and getattr(self, field_name) == target_value:
|
|
|
|
|
|
return self
|
2026-08-21 23:48:29 +08:00
|
|
|
|
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# 向上遍历祖先
|
|
|
|
|
|
current = self.parent
|
|
|
|
|
|
while current:
|
|
|
|
|
|
if getattr(current, field_name) == target_value:
|
|
|
|
|
|
return current
|
|
|
|
|
|
current = current.parent
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
# class weiuser用户角色表(models.Model):
|
|
|
|
|
|
# """城市信息表"""
|
|
|
|
|
|
# objects = models.Manager() #
|
|
|
|
|
|
# idKeyweiuser用户角色表 = models.UUIDField(primary_key=True, default=uuid8)
|
|
|
|
|
|
# id_str = models.CharField(max_length=128, default=generator.generate_str)
|
|
|
|
|
|
# user用户角色名称 = models.CharField(max_length=128, choices=weiuser用户角色表choicesStatus,
|
|
|
|
|
|
# default=weiuser用户角色表choicesStatus.普通会员.value)
|
|
|
|
|
|
# user用户的unionid = models.CharField(max_length=128, )
|
|
|
|
|
|
# dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间
|
|
|
|
|
|
# updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() )
|
|
|
|
|
|
#
|
|
|
|
|
|
# class Meta:
|
|
|
|
|
|
# db_table = "weiuser用户角色表" # 给数据表自定义一个名称;默认的会是在 应用名+类名
|
|
|
|
|
|
# app_label = models_app_name
|
|
|
|
|
|
# ordering = ["-dateAndTime", "-updateTime"]
|