123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- import hashlib
- import os
- from pathlib import PurePosixPath
- from django.contrib.auth.models import AbstractUser
- from django.core.files.base import File
- from django.db import models
- from application import dispatch
- from application.settings import BASE_DIR
- from dvadmin.utils.models import CoreModel, table_prefix
- STATUS_CHOICES = (
- (0, "禁用"),
- (1, "启用"),
- )
- class Empty(CoreModel):
- class Meta:
- db_table = table_prefix + "empty"
- verbose_name = "empty"
- verbose_name_plural = verbose_name
- ordering = ("id",)
- 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="上级部门",
- db_index=True
- )
- @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.CASCADE,
- 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="菜单状态")
- frame_out = models.BooleanField(default=False, 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 PurePosixPath("files", h[: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, null=True, blank=True, )
- file_url = models.CharField(max_length=255, blank=True, verbose_name="文件地址", help_text="文件地址")
- engine = models.CharField(max_length=100, default='local', blank=True, verbose_name="引擎", help_text="引擎")
- mime_type = models.CharField(max_length=100, blank=True, verbose_name="Mime类型", help_text="Mime类型")
- size = models.BigIntegerField(default=0, blank=True, verbose_name="文件大小", help_text="文件大小")
- md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
- @classmethod
- def save_file(cls, request, file_path, file_name, mime_type):
- # 保存到File model中
- instance = FileList()
- instance.name = file_name
- instance.engine = dispatch.get_system_config_values("file_storage.file_engine") or 'local'
- instance.file_url = os.path.join(file_path, file_name)
- instance.mime_type = mime_type
- instance.creator = request.user
- instance.modifier = request.user.id
- instance.dept_belong_id = request.user.dept_id
- file_backup = dispatch.get_system_config_values("file_storage.file_backup")
- file_engine = dispatch.get_system_config_values("file_storage.file_engine") or 'local'
- if file_backup:
- instance.url = os.path.join(file_path.replace('media/', ''), file_name)
- if file_engine == 'oss':
- from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
- with open(os.path.join(BASE_DIR, file_path, file_name), 'rb') as file:
- file_path = ali_oss_upload(file, file_name=os.path.join(file_path.replace('media/', ''), file_name))
- if file_path:
- instance.file_url = file_path
- else:
- raise ValueError("上传失败")
- elif file_engine == 'cos':
- from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
- with open(os.path.join(BASE_DIR, file_path, file_name), 'rb') as file:
- file_path = tencent_cos_upload(file, file_name=os.path.join(file_path.replace('media/', ''), file_name))
- if file_path:
- instance.file_url = file_path
- else:
- raise ValueError("上传失败")
- else:
- instance.url = os.path.join(file_path.replace('media/', ''), file_name)
- instance.save()
- return instance
- def save(self, *args, **kwargs):
- if not self.md5sum and self.url: # file is new
- md5 = hashlib.md5()
- for chunk in self.url.chunks():
- md5.update(chunk)
- self.md5sum = md5.hexdigest()
- if not self.size and self.url:
- self.size = self.url.size
- if not self.file_url:
- url = media_file_name(self, self.name)
- self.file_url = f'media/{url}'
- 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
|