506 lines
24 KiB
Python
506 lines
24 KiB
Python
import hashlib
|
|
import os
|
|
|
|
from django.contrib.auth.models import AbstractUser
|
|
from django.db import models
|
|
|
|
from application import dispatch
|
|
from dvadmin.utils.models import CoreModel, table_prefix
|
|
|
|
STATUS_CHOICES = (
|
|
(0, "禁用"),
|
|
(1, "启用"),
|
|
)
|
|
|
|
|
|
class Users(CoreModel, AbstractUser):
|
|
username = models.CharField(max_length=150, unique=True, db_index=True, verbose_name="用户账号",
|
|
help_text="用户账号")
|
|
employee_no = models.CharField(max_length=150, unique=True, db_index=True, null=True, blank=True,
|
|
verbose_name="工号", help_text="工号")
|
|
email = models.EmailField(max_length=255, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
|
|
mobile = models.CharField(max_length=255, verbose_name="电话", null=True, blank=True, help_text="电话")
|
|
avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
|
|
name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
|
|
GENDER_CHOICES = (
|
|
(0, "未知"),
|
|
(1, "男"),
|
|
(2, "女"),
|
|
)
|
|
gender = models.IntegerField(
|
|
choices=GENDER_CHOICES, default=0, verbose_name="性别", null=True, blank=True, help_text="性别"
|
|
)
|
|
USER_TYPE = (
|
|
(0, "后台用户"),
|
|
(1, "前台用户"),
|
|
)
|
|
user_type = models.IntegerField(
|
|
choices=USER_TYPE, default=0, verbose_name="用户类型", null=True, blank=True, help_text="用户类型"
|
|
)
|
|
post = models.ManyToManyField(to="Post", blank=True, verbose_name="关联岗位", db_constraint=False,
|
|
help_text="关联岗位")
|
|
role = models.ManyToManyField(to="Role", blank=True, verbose_name="关联角色", db_constraint=False,
|
|
help_text="关联角色")
|
|
dept = models.ForeignKey(
|
|
to="Dept",
|
|
verbose_name="所属部门",
|
|
on_delete=models.PROTECT,
|
|
db_constraint=False,
|
|
null=True,
|
|
blank=True,
|
|
help_text="关联部门",
|
|
)
|
|
last_token = models.CharField(max_length=255, null=True, blank=True, verbose_name="最后一次登录Token",
|
|
help_text="最后一次登录Token")
|
|
|
|
def set_password(self, raw_password):
|
|
super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest())
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_users"
|
|
verbose_name = "用户表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("-create_datetime",)
|
|
|
|
|
|
class Post(CoreModel):
|
|
name = models.CharField(null=False, max_length=64, verbose_name="岗位名称", help_text="岗位名称")
|
|
code = models.CharField(max_length=32, verbose_name="岗位编码", help_text="岗位编码")
|
|
sort = models.IntegerField(default=1, verbose_name="岗位顺序", help_text="岗位顺序")
|
|
STATUS_CHOICES = (
|
|
(0, "离职"),
|
|
(1, "在职"),
|
|
)
|
|
status = models.IntegerField(choices=STATUS_CHOICES, default=1, verbose_name="岗位状态", help_text="岗位状态")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_post"
|
|
verbose_name = "岗位表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("sort",)
|
|
|
|
|
|
class Role(CoreModel):
|
|
name = models.CharField(max_length=64, verbose_name="角色名称", help_text="角色名称")
|
|
key = models.CharField(max_length=64, unique=True, verbose_name="权限字符", help_text="权限字符")
|
|
sort = models.IntegerField(default=1, verbose_name="角色顺序", help_text="角色顺序")
|
|
status = models.BooleanField(default=True, verbose_name="角色状态", help_text="角色状态")
|
|
admin = models.BooleanField(default=False, verbose_name="是否为admin", help_text="是否为admin")
|
|
DATASCOPE_CHOICES = (
|
|
(0, "仅本人数据权限"),
|
|
(1, "本部门及以下数据权限"),
|
|
(2, "本部门数据权限"),
|
|
(3, "全部数据权限"),
|
|
(4, "自定数据权限"),
|
|
)
|
|
data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围",
|
|
help_text="数据权限范围")
|
|
remark = models.TextField(verbose_name="备注", help_text="备注", null=True, blank=True)
|
|
dept = models.ManyToManyField(to="Dept", verbose_name="数据权限-关联部门", db_constraint=False,
|
|
help_text="数据权限-关联部门")
|
|
menu = models.ManyToManyField(to="Menu", verbose_name="关联菜单", db_constraint=False, help_text="关联菜单")
|
|
permission = models.ManyToManyField(
|
|
to="MenuButton", verbose_name="关联菜单的接口按钮", db_constraint=False, help_text="关联菜单的接口按钮"
|
|
)
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_role"
|
|
verbose_name = "角色表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("sort",)
|
|
|
|
|
|
class Dept(CoreModel):
|
|
name = models.CharField(max_length=64, verbose_name="部门名称", help_text="部门名称")
|
|
key = models.CharField(max_length=64, unique=True, null=True, blank=True, verbose_name="关联字符",
|
|
help_text="关联字符")
|
|
sort = models.IntegerField(default=1, verbose_name="显示排序", help_text="显示排序")
|
|
owner = models.CharField(max_length=32, verbose_name="负责人", null=True, blank=True, help_text="负责人")
|
|
phone = models.CharField(max_length=32, verbose_name="联系电话", null=True, blank=True, help_text="联系电话")
|
|
email = models.EmailField(max_length=32, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
|
|
status = models.BooleanField(default=True, verbose_name="部门状态", null=True, blank=True, help_text="部门状态")
|
|
parent = models.ForeignKey(
|
|
to="Dept",
|
|
on_delete=models.CASCADE,
|
|
default=None,
|
|
verbose_name="上级部门",
|
|
db_constraint=False,
|
|
null=True,
|
|
blank=True,
|
|
help_text="上级部门",
|
|
)
|
|
|
|
@classmethod
|
|
def recursion_dept_info(cls, dept_id: int, dept_all_list=None, dept_list=None):
|
|
"""
|
|
递归获取部门的所有下级部门
|
|
:param dept_id: 需要获取的id
|
|
:param dept_all_list: 所有列表
|
|
:param dept_list: 递归list
|
|
:return:
|
|
"""
|
|
if not dept_all_list:
|
|
dept_all_list = Dept.objects.values("id", "parent")
|
|
if dept_list is None:
|
|
dept_list = [dept_id]
|
|
for ele in dept_all_list:
|
|
if ele.get("parent") == dept_id:
|
|
dept_list.append(ele.get("id"))
|
|
cls.recursion_dept_info(ele.get("id"), dept_all_list, dept_list)
|
|
return list(set(dept_list))
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_dept"
|
|
verbose_name = "部门表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("sort",)
|
|
|
|
|
|
class Menu(CoreModel):
|
|
parent = models.ForeignKey(
|
|
to="Menu",
|
|
on_delete=models.PROTECT,
|
|
verbose_name="上级菜单",
|
|
null=True,
|
|
blank=True,
|
|
db_constraint=False,
|
|
help_text="上级菜单",
|
|
)
|
|
icon = models.CharField(max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标")
|
|
name = models.CharField(max_length=64, verbose_name="菜单名称", help_text="菜单名称")
|
|
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
|
|
ISLINK_CHOICES = (
|
|
(0, "否"),
|
|
(1, "是"),
|
|
)
|
|
is_link = models.BooleanField(default=False, verbose_name="是否外链", help_text="是否外链")
|
|
is_catalog = models.BooleanField(default=False, verbose_name="是否目录", help_text="是否目录")
|
|
web_path = models.CharField(max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址")
|
|
component = models.CharField(max_length=128, verbose_name="组件地址", null=True, blank=True, help_text="组件地址")
|
|
component_name = models.CharField(max_length=50, verbose_name="组件名称", null=True, blank=True,
|
|
help_text="组件名称")
|
|
status = models.BooleanField(default=True, blank=True, verbose_name="菜单状态", help_text="菜单状态")
|
|
cache = models.BooleanField(default=False, blank=True, verbose_name="是否页面缓存", help_text="是否页面缓存")
|
|
visible = models.BooleanField(default=True, blank=True, verbose_name="侧边栏中是否显示",
|
|
help_text="侧边栏中是否显示")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_menu"
|
|
verbose_name = "菜单表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("sort",)
|
|
|
|
|
|
class MenuButton(CoreModel):
|
|
menu = models.ForeignKey(
|
|
to="Menu",
|
|
db_constraint=False,
|
|
related_name="menuPermission",
|
|
on_delete=models.PROTECT,
|
|
verbose_name="关联菜单",
|
|
help_text="关联菜单",
|
|
)
|
|
name = models.CharField(max_length=64, verbose_name="名称", help_text="名称")
|
|
value = models.CharField(max_length=64, verbose_name="权限值", help_text="权限值")
|
|
api = models.CharField(max_length=200, verbose_name="接口地址", help_text="接口地址")
|
|
METHOD_CHOICES = (
|
|
(0, "GET"),
|
|
(1, "POST"),
|
|
(2, "PUT"),
|
|
(3, "DELETE"),
|
|
)
|
|
method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True,
|
|
help_text="接口请求方法")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_menu_button"
|
|
verbose_name = "菜单权限表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("-name",)
|
|
|
|
|
|
class Dictionary(CoreModel):
|
|
TYPE_LIST = (
|
|
(0, "text"),
|
|
(1, "number"),
|
|
(2, "date"),
|
|
(3, "datetime"),
|
|
(4, "time"),
|
|
(5, "files"),
|
|
(6, "boolean"),
|
|
(7, "images"),
|
|
)
|
|
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称")
|
|
value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号",
|
|
help_text="字典编号/实际值")
|
|
parent = models.ForeignKey(
|
|
to="self",
|
|
related_name="sublist",
|
|
db_constraint=False,
|
|
on_delete=models.PROTECT,
|
|
blank=True,
|
|
null=True,
|
|
verbose_name="父级",
|
|
help_text="父级",
|
|
)
|
|
type = models.IntegerField(choices=TYPE_LIST, default=0, verbose_name="数据值类型", help_text="数据值类型")
|
|
color = models.CharField(max_length=20, blank=True, null=True, verbose_name="颜色", help_text="颜色")
|
|
is_value = models.BooleanField(default=False, verbose_name="是否为value值",
|
|
help_text="是否为value值,用来做具体值存放")
|
|
status = models.BooleanField(default=True, verbose_name="状态", help_text="状态")
|
|
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
|
|
remark = models.CharField(max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_dictionary"
|
|
verbose_name = "字典表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("sort",)
|
|
|
|
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
|
super().save(force_insert, force_update, using, update_fields)
|
|
dispatch.refresh_dictionary() # 有更新则刷新字典配置
|
|
|
|
def delete(self, using=None, keep_parents=False):
|
|
res = super().delete(using, keep_parents)
|
|
dispatch.refresh_dictionary()
|
|
return res
|
|
|
|
|
|
class OperationLog(CoreModel):
|
|
request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True,
|
|
help_text="请求模块")
|
|
request_path = models.CharField(max_length=400, verbose_name="请求地址", null=True, blank=True,
|
|
help_text="请求地址")
|
|
request_body = models.TextField(verbose_name="请求参数", null=True, blank=True, help_text="请求参数")
|
|
request_method = models.CharField(max_length=8, verbose_name="请求方式", null=True, blank=True,
|
|
help_text="请求方式")
|
|
request_msg = models.TextField(verbose_name="操作说明", null=True, blank=True, help_text="操作说明")
|
|
request_ip = models.CharField(max_length=32, verbose_name="请求ip地址", null=True, blank=True,
|
|
help_text="请求ip地址")
|
|
request_browser = models.CharField(max_length=64, verbose_name="请求浏览器", null=True, blank=True,
|
|
help_text="请求浏览器")
|
|
response_code = models.CharField(max_length=32, verbose_name="响应状态码", null=True, blank=True,
|
|
help_text="响应状态码")
|
|
request_os = models.CharField(max_length=64, verbose_name="操作系统", null=True, blank=True, help_text="操作系统")
|
|
json_result = models.TextField(verbose_name="返回信息", null=True, blank=True, help_text="返回信息")
|
|
status = models.BooleanField(default=False, verbose_name="响应状态", help_text="响应状态")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_operation_log"
|
|
verbose_name = "操作日志"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("-create_datetime",)
|
|
|
|
|
|
def media_file_name(instance, filename):
|
|
h = instance.md5sum
|
|
basename, ext = os.path.splitext(filename)
|
|
return os.path.join("files", h[0:1], h[1:2], h + ext.lower())
|
|
|
|
|
|
class FileList(CoreModel):
|
|
name = models.CharField(max_length=200, null=True, blank=True, verbose_name="名称", help_text="名称")
|
|
url = models.FileField(upload_to=media_file_name)
|
|
md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
|
|
|
|
def save(self, *args, **kwargs):
|
|
if not self.md5sum: # file is new
|
|
md5 = hashlib.md5()
|
|
for chunk in self.url.chunks():
|
|
md5.update(chunk)
|
|
self.md5sum = md5.hexdigest()
|
|
super(FileList, self).save(*args, **kwargs)
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_file_list"
|
|
verbose_name = "文件管理"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("-create_datetime",)
|
|
|
|
|
|
class Area(CoreModel):
|
|
name = models.CharField(max_length=100, verbose_name="名称", help_text="名称")
|
|
code = models.CharField(max_length=20, verbose_name="地区编码", help_text="地区编码", unique=True, db_index=True)
|
|
level = models.BigIntegerField(verbose_name="地区层级(1省份 2城市 3区县 4乡级)",
|
|
help_text="地区层级(1省份 2城市 3区县 4乡级)")
|
|
pinyin = models.CharField(max_length=255, verbose_name="拼音", help_text="拼音")
|
|
initials = models.CharField(max_length=20, verbose_name="首字母", help_text="首字母")
|
|
enable = models.BooleanField(default=True, verbose_name="是否启用", help_text="是否启用")
|
|
pcode = models.ForeignKey(
|
|
to="self",
|
|
verbose_name="父地区编码",
|
|
to_field="code",
|
|
on_delete=models.PROTECT,
|
|
db_constraint=False,
|
|
null=True,
|
|
blank=True,
|
|
help_text="父地区编码",
|
|
)
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_area"
|
|
verbose_name = "地区表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("code",)
|
|
|
|
def __str__(self):
|
|
return f"{self.name}"
|
|
|
|
|
|
class ApiWhiteList(CoreModel):
|
|
url = models.CharField(max_length=200, help_text="url地址", verbose_name="url")
|
|
METHOD_CHOICES = (
|
|
(0, "GET"),
|
|
(1, "POST"),
|
|
(2, "PUT"),
|
|
(3, "DELETE"),
|
|
)
|
|
method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True,
|
|
help_text="接口请求方法")
|
|
enable_datasource = models.BooleanField(default=True, verbose_name="激活数据权限", help_text="激活数据权限",
|
|
blank=True)
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "api_white_list"
|
|
verbose_name = "接口白名单"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("-create_datetime",)
|
|
|
|
|
|
class SystemConfig(CoreModel):
|
|
parent = models.ForeignKey(
|
|
to="self",
|
|
verbose_name="父级",
|
|
on_delete=models.PROTECT,
|
|
db_constraint=False,
|
|
null=True,
|
|
blank=True,
|
|
help_text="父级",
|
|
)
|
|
title = models.CharField(max_length=50, verbose_name="标题", help_text="标题")
|
|
key = models.CharField(max_length=200, verbose_name="键", help_text="键", db_index=True)
|
|
value = models.JSONField(max_length=500, verbose_name="值", help_text="值", null=True, blank=True)
|
|
sort = models.IntegerField(default=0, verbose_name="排序", help_text="排序", blank=True)
|
|
status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态")
|
|
data_options = models.JSONField(verbose_name="数据options", help_text="数据options", null=True, blank=True)
|
|
FORM_ITEM_TYPE_LIST = (
|
|
(0, "text"),
|
|
(1, "datetime"),
|
|
(2, "date"),
|
|
(3, "textarea"),
|
|
(4, "select"),
|
|
(5, "checkbox"),
|
|
(6, "radio"),
|
|
(7, "img"),
|
|
(8, "file"),
|
|
(9, "switch"),
|
|
(10, "number"),
|
|
(11, "array"),
|
|
(12, "imgs"),
|
|
(13, "foreignkey"),
|
|
(14, "manytomany"),
|
|
(15, "time"),
|
|
)
|
|
form_item_type = models.IntegerField(
|
|
choices=FORM_ITEM_TYPE_LIST, verbose_name="表单类型", help_text="表单类型", default=0, blank=True
|
|
)
|
|
rule = models.JSONField(null=True, blank=True, verbose_name="校验规则", help_text="校验规则")
|
|
placeholder = models.CharField(max_length=100, null=True, blank=True, verbose_name="提示信息", help_text="提示信息")
|
|
setting = models.JSONField(null=True, blank=True, verbose_name="配置", help_text="配置")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_config"
|
|
verbose_name = "系统配置表"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("sort",)
|
|
unique_together = (("key", "parent_id"),)
|
|
|
|
def __str__(self):
|
|
return f"{self.title}"
|
|
|
|
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
|
# from application.websocketConfig import websocket_push
|
|
# websocket_push("dvadmin", message={"sender": 'system', "contentType": 'SYSTEM',
|
|
# "content": '系统配置有变化~', "systemConfig": True})
|
|
|
|
super().save(force_insert, force_update, using, update_fields)
|
|
dispatch.refresh_system_config() # 有更新则刷新系统配置
|
|
|
|
def delete(self, using=None, keep_parents=False):
|
|
res = super().delete(using, keep_parents)
|
|
dispatch.refresh_system_config()
|
|
from application.websocketConfig import websocket_push
|
|
websocket_push("dvadmin", message={"sender": 'system', "contentType": 'SYSTEM',
|
|
"content": '系统配置有变化~', "systemConfig": True})
|
|
|
|
return res
|
|
|
|
|
|
class LoginLog(CoreModel):
|
|
LOGIN_TYPE_CHOICES = (
|
|
(1, "普通登录"),
|
|
(2, "普通扫码登录"),
|
|
(3, "微信扫码登录"),
|
|
(4, "飞书扫码登录"),
|
|
(5, "钉钉扫码登录"),
|
|
(6, "短信登录")
|
|
)
|
|
username = models.CharField(max_length=150, verbose_name="登录用户名", null=True, blank=True, help_text="登录用户名")
|
|
ip = models.CharField(max_length=32, verbose_name="登录ip", null=True, blank=True, help_text="登录ip")
|
|
agent = models.TextField(verbose_name="agent信息", null=True, blank=True, help_text="agent信息")
|
|
browser = models.CharField(max_length=200, verbose_name="浏览器名", null=True, blank=True, help_text="浏览器名")
|
|
os = models.CharField(max_length=200, verbose_name="操作系统", null=True, blank=True, help_text="操作系统")
|
|
continent = models.CharField(max_length=50, verbose_name="州", null=True, blank=True, help_text="州")
|
|
country = models.CharField(max_length=50, verbose_name="国家", null=True, blank=True, help_text="国家")
|
|
province = models.CharField(max_length=50, verbose_name="省份", null=True, blank=True, help_text="省份")
|
|
city = models.CharField(max_length=50, verbose_name="城市", null=True, blank=True, help_text="城市")
|
|
district = models.CharField(max_length=50, verbose_name="县区", null=True, blank=True, help_text="县区")
|
|
isp = models.CharField(max_length=50, verbose_name="运营商", null=True, blank=True, help_text="运营商")
|
|
area_code = models.CharField(max_length=50, verbose_name="区域代码", null=True, blank=True, help_text="区域代码")
|
|
country_english = models.CharField(max_length=50, verbose_name="英文全称", null=True, blank=True,
|
|
help_text="英文全称")
|
|
country_code = models.CharField(max_length=50, verbose_name="简称", null=True, blank=True, help_text="简称")
|
|
longitude = models.CharField(max_length=50, verbose_name="经度", null=True, blank=True, help_text="经度")
|
|
latitude = models.CharField(max_length=50, verbose_name="纬度", null=True, blank=True, help_text="纬度")
|
|
login_type = models.IntegerField(default=1, choices=LOGIN_TYPE_CHOICES, verbose_name="登录类型",
|
|
help_text="登录类型")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "system_login_log"
|
|
verbose_name = "登录日志"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("-create_datetime",)
|
|
|
|
|
|
class MessageCenter(CoreModel):
|
|
title = models.CharField(max_length=100, verbose_name="标题", help_text="标题")
|
|
content = models.TextField(verbose_name="内容", help_text="内容")
|
|
target_type = models.IntegerField(default=0, verbose_name="目标类型", help_text="目标类型")
|
|
target_user = models.ManyToManyField(to=Users, related_name='user', through='MessageCenterTargetUser',
|
|
through_fields=('messagecenter', 'users'), blank=True, verbose_name="目标用户",
|
|
help_text="目标用户")
|
|
target_dept = models.ManyToManyField(to=Dept, blank=True, db_constraint=False,
|
|
verbose_name="目标部门", help_text="目标部门")
|
|
target_role = models.ManyToManyField(to=Role, blank=True, db_constraint=False,
|
|
verbose_name="目标角色", help_text="目标角色")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "message_center"
|
|
verbose_name = "消息中心"
|
|
verbose_name_plural = verbose_name
|
|
ordering = ("-create_datetime",)
|
|
|
|
|
|
class MessageCenterTargetUser(CoreModel):
|
|
users = models.ForeignKey(Users, related_name="target_user", on_delete=models.CASCADE, db_constraint=False,
|
|
verbose_name="关联用户表", help_text="关联用户表")
|
|
messagecenter = models.ForeignKey(MessageCenter, on_delete=models.CASCADE, db_constraint=False,
|
|
verbose_name="关联消息中心表", help_text="关联消息中心表")
|
|
is_read = models.BooleanField(default=False, blank=True, null=True, verbose_name="是否已读", help_text="是否已读")
|
|
|
|
class Meta:
|
|
db_table = table_prefix + "message_center_target_user"
|
|
verbose_name = "消息中心目标用户表"
|
|
verbose_name_plural = verbose_name
|