增加预算表的显示功能
This commit is contained in:
@@ -1,182 +1,327 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
class Branch(models.Model):
|
||||
CATEGORY_CHOICES = (
|
||||
('A型', 'A型'),
|
||||
('B型', 'B型'),
|
||||
('C型', 'C型'),
|
||||
('不适用', '不适用'),
|
||||
)
|
||||
name = models.CharField(max_length=255, unique=True, verbose_name='分支机构名称')
|
||||
location = models.CharField(max_length=255, verbose_name='所在省份')
|
||||
contact_info = models.CharField(max_length=255, verbose_name='主要联系人')
|
||||
description = models.TextField(blank=True, verbose_name='备注')
|
||||
background_color = models.CharField(max_length=7, default='#EFF6FF', verbose_name='背景色',
|
||||
help_text='使用#RRGGBB格式的颜色代码')
|
||||
category = models.CharField(max_length=10, choices=CATEGORY_CHOICES, default='C型', verbose_name='分类')
|
||||
is_mature = models.BooleanField(default=False, verbose_name='是否成熟')
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name} 💼' if self.is_mature else self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '分支机构'
|
||||
verbose_name_plural = '分支机构(基础信息)'
|
||||
|
||||
|
||||
class Contact(models.Model):
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, verbose_name='分支机构')
|
||||
CATEGORY_CHOICES = [
|
||||
('机房/设备间巡检人', '机房/设备间巡检人'),
|
||||
('信息安全联系人', '信息安全联系人'),
|
||||
('兼岗', '兼岗'),
|
||||
('安全员', '安全员')
|
||||
# 可以添加更多类别
|
||||
]
|
||||
# 修改为支持多选的 CharField
|
||||
category = models.CharField(
|
||||
max_length=255, # 增大长度(原50可能不足)
|
||||
choices=CATEGORY_CHOICES,
|
||||
verbose_name='联系人分类',
|
||||
help_text='按住 Ctrl/Command 键多选(值将以逗号分隔存储)'
|
||||
)
|
||||
name = models.CharField(max_length=255, verbose_name='姓名')
|
||||
phone = models.CharField(max_length=20, verbose_name='电话')
|
||||
email = models.EmailField(blank=True, verbose_name='邮箱,可不填')
|
||||
description = models.TextField(blank=True, verbose_name='描述,可不填')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '联系人群'
|
||||
verbose_name_plural = '联系人群'
|
||||
|
||||
|
||||
class Activity(models.Model):
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, verbose_name='分支机构')
|
||||
name = models.CharField(max_length=255, verbose_name='活动名称')
|
||||
scope = models.CharField(max_length=255, choices=(
|
||||
('新建', '新建'),
|
||||
('搬迁', '搬迁'),
|
||||
('原址装修', '原址装修'),
|
||||
('撤销', '撤销'),
|
||||
('其他技术问题', '其他技术问题')
|
||||
|
||||
), verbose_name='活动类型')
|
||||
start_time = models.DateField(verbose_name='开始日期')
|
||||
end_time = models.DateField(blank=True, null=True, verbose_name='结束日期') # 可以为空,表示活动尚未结束
|
||||
location = models.CharField(max_length=255, verbose_name='所在地点')
|
||||
description = models.TextField(verbose_name='其它内容')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '运营活动内容'
|
||||
verbose_name_plural = '运营活动内容(新建搬迁装修和技术)'
|
||||
|
||||
|
||||
class EquipmentImage(models.Model):
|
||||
branch = models.ForeignKey(Branch, related_name='equipment_images', on_delete=models.CASCADE)
|
||||
image = models.ImageField(upload_to='equipment_room_images/')
|
||||
uploaded_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"设备间图片 {self.id} - {self.branch.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '设备间图'
|
||||
verbose_name_plural = '设备间图'
|
||||
|
||||
|
||||
# 图纸的类
|
||||
class Drawing(models.Model):
|
||||
branch = models.ForeignKey(Branch, related_name='drawings', on_delete=models.CASCADE)
|
||||
image = models.ImageField(upload_to='drawings/')
|
||||
uploaded_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"图纸 {self.id} - {self.branch.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '图纸'
|
||||
verbose_name_plural = '图纸'
|
||||
|
||||
|
||||
# 公共电子屏
|
||||
class PublicScreen(models.Model):
|
||||
SCREEN_TYPES = (
|
||||
('marquee', '跑马灯'),
|
||||
('advertisement', '广告屏'),
|
||||
('information', '信息发布屏'),
|
||||
)
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, related_name='public_screens')
|
||||
image = models.ImageField(upload_to='public_screen_images/', null=True, blank=True)
|
||||
screen_type = models.CharField(max_length=20, choices=SCREEN_TYPES, verbose_name='功能类型', null=True, blank=True)
|
||||
description = models.TextField(blank=True, null=True, verbose_name='功能描述')
|
||||
last_drill = models.ForeignKey('Event', on_delete=models.SET_NULL, blank=True, null=True, related_name='public_screens', verbose_name='最后演练事件')
|
||||
created_at = models.DateTimeField(default=timezone.now)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.branch.name} - {self.get_screen_type_display()} {self.id}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '公共电子屏'
|
||||
verbose_name_plural = '公共电子屏'
|
||||
|
||||
|
||||
class Event(models.Model):
|
||||
branches = models.ManyToManyField(Branch, related_name='events', verbose_name='分支机构')
|
||||
name = models.CharField(max_length=255, verbose_name='事件名称')
|
||||
start_time = models.DateField(verbose_name='开始时间')
|
||||
end_time = models.DateField(blank=True, null=True, verbose_name='结束时间') # 可以为空,表示活动尚未结束
|
||||
description = models.TextField(verbose_name='事件描述')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '运营事件'
|
||||
verbose_name_plural = '运营事件(其它)'
|
||||
|
||||
|
||||
class VideoTerminal(models.Model):
|
||||
TERMINAL_TYPES = (
|
||||
('polycom', '宝利通终端'),
|
||||
('zte', '中兴终端'),
|
||||
('logitech', '罗技摄像头'),
|
||||
('laptop_tv', '笔记本加电视'),
|
||||
('laptop_projector', '笔记本加投影仪'),
|
||||
('other', '其它'),
|
||||
)
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, related_name='video_terminals', verbose_name='分支机构')
|
||||
terminal_type = models.CharField(max_length=20, choices=TERMINAL_TYPES, verbose_name='设备类型')
|
||||
description = models.TextField(blank=True, verbose_name='设备描述')
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.branch.name} - {self.get_terminal_type_display()}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '视频设备终端'
|
||||
verbose_name_plural = '视频设备终端'
|
||||
|
||||
|
||||
class Evaluation(models.Model):
|
||||
activity = models.ForeignKey(Activity, on_delete=models.CASCADE)
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE)
|
||||
score = models.DecimalField(max_digits=4, decimal_places=2)
|
||||
comment = models.TextField()
|
||||
file_path = models.CharField(max_length=255, blank=True, null=True)
|
||||
status = models.CharField(max_length=20,
|
||||
choices=(('pending', '待审核'), ('approved', '已通过'), ('rejected', '已拒绝')),
|
||||
default='pending')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.activity.name} - {self.branch.name}"
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
class Branch(models.Model):
|
||||
CATEGORY_CHOICES = (
|
||||
('A型', 'A型'),
|
||||
('B型', 'B型'),
|
||||
('C型', 'C型'),
|
||||
('不适用', '不适用'),
|
||||
)
|
||||
name = models.CharField(max_length=255, unique=True, verbose_name='分支机构名称')
|
||||
location = models.CharField(max_length=255, verbose_name='所在省份')
|
||||
contact_info = models.CharField(max_length=255, verbose_name='主要联系人')
|
||||
description = models.TextField(blank=True, verbose_name='备注')
|
||||
background_color = models.CharField(max_length=7, default='#EFF6FF', verbose_name='背景色',
|
||||
help_text='使用#RRGGBB格式的颜色代码')
|
||||
category = models.CharField(max_length=10, choices=CATEGORY_CHOICES, default='C型', verbose_name='分类')
|
||||
is_mature = models.BooleanField(default=False, verbose_name='是否成熟')
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name} 💼' if self.is_mature else self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '分支机构'
|
||||
verbose_name_plural = '分支机构(基础信息)'
|
||||
|
||||
|
||||
class Contact(models.Model):
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, verbose_name='分支机构')
|
||||
CATEGORY_CHOICES = [
|
||||
('机房/设备间巡检人', '机房/设备间巡检人'),
|
||||
('信息安全联系人', '信息安全联系人'),
|
||||
('兼岗', '兼岗'),
|
||||
('安全员', '安全员')
|
||||
# 可以添加更多类别
|
||||
]
|
||||
# 修改为支持多选的 CharField
|
||||
category = models.CharField(
|
||||
max_length=255, # 增大长度(原50可能不足)
|
||||
choices=CATEGORY_CHOICES,
|
||||
verbose_name='联系人分类',
|
||||
help_text='按住 Ctrl/Command 键多选(值将以逗号分隔存储)'
|
||||
)
|
||||
name = models.CharField(max_length=255, verbose_name='姓名')
|
||||
phone = models.CharField(max_length=20, verbose_name='电话')
|
||||
email = models.EmailField(blank=True, verbose_name='邮箱,可不填')
|
||||
description = models.TextField(blank=True, verbose_name='描述,可不填')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '联系人群'
|
||||
verbose_name_plural = '联系人群'
|
||||
|
||||
|
||||
class Activity(models.Model):
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, verbose_name='分支机构')
|
||||
name = models.CharField(max_length=255, verbose_name='活动名称')
|
||||
scope = models.CharField(max_length=255, choices=(
|
||||
('新建', '新建'),
|
||||
('搬迁', '搬迁'),
|
||||
('原址装修', '原址装修'),
|
||||
('撤销', '撤销'),
|
||||
('其他技术问题', '其他技术问题')
|
||||
|
||||
), verbose_name='活动类型')
|
||||
start_time = models.DateField(verbose_name='开始日期')
|
||||
end_time = models.DateField(blank=True, null=True, verbose_name='结束日期') # 可以为空,表示活动尚未结束
|
||||
location = models.CharField(max_length=255, verbose_name='所在地点')
|
||||
description = models.TextField(verbose_name='其它内容')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '运营活动内容'
|
||||
verbose_name_plural = '运营活动内容(新建搬迁装修和技术)'
|
||||
|
||||
|
||||
class EquipmentImage(models.Model):
|
||||
branch = models.ForeignKey(Branch, related_name='equipment_images', on_delete=models.CASCADE)
|
||||
image = models.ImageField(upload_to='equipment_room_images/')
|
||||
uploaded_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"设备间图片 {self.id} - {self.branch.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '设备间图'
|
||||
verbose_name_plural = '设备间图'
|
||||
|
||||
|
||||
# 图纸的类
|
||||
class Drawing(models.Model):
|
||||
branch = models.ForeignKey(Branch, related_name='drawings', on_delete=models.CASCADE)
|
||||
image = models.ImageField(upload_to='drawings/')
|
||||
uploaded_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"图纸 {self.id} - {self.branch.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '图纸'
|
||||
verbose_name_plural = '图纸'
|
||||
|
||||
|
||||
# 公共电子屏
|
||||
class PublicScreen(models.Model):
|
||||
SCREEN_TYPES = (
|
||||
('marquee', '跑马灯'),
|
||||
('advertisement', '广告屏'),
|
||||
('information', '信息发布屏'),
|
||||
)
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, related_name='public_screens')
|
||||
image = models.ImageField(upload_to='public_screen_images/', null=True, blank=True)
|
||||
screen_type = models.CharField(max_length=20, choices=SCREEN_TYPES, verbose_name='功能类型', null=True, blank=True)
|
||||
description = models.TextField(blank=True, null=True, verbose_name='功能描述')
|
||||
last_drill = models.ForeignKey('Event', on_delete=models.SET_NULL, blank=True, null=True, related_name='public_screens', verbose_name='最后演练事件')
|
||||
created_at = models.DateTimeField(default=timezone.now)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.branch.name} - {self.get_screen_type_display()} {self.id}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '公共电子屏'
|
||||
verbose_name_plural = '公共电子屏'
|
||||
|
||||
|
||||
class Event(models.Model):
|
||||
branches = models.ManyToManyField(Branch, related_name='events', verbose_name='分支机构')
|
||||
name = models.CharField(max_length=255, verbose_name='事件名称')
|
||||
start_time = models.DateField(verbose_name='开始时间')
|
||||
end_time = models.DateField(blank=True, null=True, verbose_name='结束时间') # 可以为空,表示活动尚未结束
|
||||
description = models.TextField(verbose_name='事件描述')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '运营事件'
|
||||
verbose_name_plural = '运营事件(其它)'
|
||||
|
||||
|
||||
class VideoTerminal(models.Model):
|
||||
TERMINAL_TYPES = (
|
||||
('polycom', '宝利通终端'),
|
||||
('zte', '中兴终端'),
|
||||
('logitech', '罗技摄像头'),
|
||||
('laptop_tv', '笔记本加电视'),
|
||||
('laptop_projector', '笔记本加投影仪'),
|
||||
('other', '其它'),
|
||||
)
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, related_name='video_terminals', verbose_name='分支机构')
|
||||
terminal_type = models.CharField(max_length=20, choices=TERMINAL_TYPES, verbose_name='设备类型')
|
||||
description = models.TextField(blank=True, verbose_name='设备描述')
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.branch.name} - {self.get_terminal_type_display()}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '视频设备终端'
|
||||
verbose_name_plural = '视频设备终端'
|
||||
|
||||
|
||||
class Evaluation(models.Model):
|
||||
activity = models.ForeignKey(Activity, on_delete=models.CASCADE)
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE)
|
||||
score = models.DecimalField(max_digits=4, decimal_places=2)
|
||||
comment = models.TextField()
|
||||
file_path = models.CharField(max_length=255, blank=True, null=True)
|
||||
status = models.CharField(max_length=20,
|
||||
choices=(('pending', '待审核'), ('approved', '已通过'), ('rejected', '已拒绝')),
|
||||
default='pending')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.activity.name} - {self.branch.name}"
|
||||
|
||||
|
||||
# 预算相关模型
|
||||
class Budget(models.Model):
|
||||
"""预算主表"""
|
||||
branch = models.ForeignKey(Branch, on_delete=models.CASCADE, verbose_name='分支机构')
|
||||
name = models.CharField(max_length=255, verbose_name='预算名称')
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
total_budget = models.DecimalField(max_digits=15, decimal_places=2, default=0, verbose_name='总预算')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.branch.name} - {self.name} 预算"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '预算主表'
|
||||
verbose_name_plural = '预算主表'
|
||||
|
||||
|
||||
class EquipmentBudget(models.Model):
|
||||
"""设备预算明细"""
|
||||
BUDGET_TYPES = (
|
||||
('本地询价采购', '本地询价采购'),
|
||||
('订单采购', '订单采购'),
|
||||
('按照总部配置要求本地询价采购', '按照总部配置要求本地询价采购'),
|
||||
('本地询价采购或订单采购', '本地询价采购或订单采购')
|
||||
)
|
||||
budget = models.ForeignKey(Budget, related_name='equipment_budgets', on_delete=models.CASCADE, verbose_name='预算主表')
|
||||
project = models.CharField(max_length=255, verbose_name='项目')
|
||||
model = models.CharField(max_length=255, verbose_name='型号')
|
||||
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='单价')
|
||||
procurement_method = models.CharField(max_length=50, choices=BUDGET_TYPES, verbose_name='采购方式')
|
||||
quantity = models.IntegerField(default=1, verbose_name='数量')
|
||||
subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name='小计')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.subtotal = self.unit_price * self.quantity
|
||||
super().save(*args, **kwargs)
|
||||
# 更新预算主表的总预算
|
||||
self.update_total_budget()
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
# 更新预算主表的总预算
|
||||
self.update_total_budget()
|
||||
|
||||
def update_total_budget(self):
|
||||
"""更新预算主表的总预算"""
|
||||
total = self.budget.equipment_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
|
||||
total += self.budget.infrastructure_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
|
||||
self.budget.total_budget = total
|
||||
self.budget.save()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.project} - {self.model}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '设备预算明细'
|
||||
verbose_name_plural = '设备预算明细'
|
||||
|
||||
|
||||
class InfrastructureBudget(models.Model):
|
||||
"""基础设施预算明细"""
|
||||
budget = models.ForeignKey(Budget, related_name='infrastructure_budgets', on_delete=models.CASCADE, verbose_name='预算主表')
|
||||
name = models.CharField(max_length=255, verbose_name='名称')
|
||||
remarks = models.TextField(blank=True, verbose_name='备注')
|
||||
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='单价')
|
||||
unit = models.CharField(max_length=20, verbose_name='单位')
|
||||
description = models.TextField(blank=True, verbose_name='说明')
|
||||
quantity = models.IntegerField(default=1, verbose_name='数量')
|
||||
subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name='小计')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.subtotal = self.unit_price * self.quantity
|
||||
super().save(*args, **kwargs)
|
||||
# 更新预算主表的总预算
|
||||
self.update_total_budget()
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
# 更新预算主表的总预算
|
||||
self.update_total_budget()
|
||||
|
||||
def update_total_budget(self):
|
||||
"""更新预算主表的总预算"""
|
||||
total = self.budget.equipment_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
|
||||
total += self.budget.infrastructure_budgets.aggregate(total=models.Sum('subtotal'))['total'] or 0
|
||||
self.budget.total_budget = total
|
||||
self.budget.save()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '基础设施预算明细'
|
||||
verbose_name_plural = '基础设施预算明细'
|
||||
|
||||
|
||||
class BudgetTemplate(models.Model):
|
||||
"""预算模板"""
|
||||
name = models.CharField(max_length=255, verbose_name='模板名称')
|
||||
description = models.TextField(blank=True, verbose_name='模板描述')
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
is_default = models.BooleanField(default=False, verbose_name='是否默认模板')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '预算模板'
|
||||
verbose_name_plural = '预算模板'
|
||||
|
||||
|
||||
class TemplateEquipmentItem(models.Model):
|
||||
"""模板设备项"""
|
||||
template = models.ForeignKey(BudgetTemplate, related_name='equipment_items', on_delete=models.CASCADE, verbose_name='模板')
|
||||
project = models.CharField(max_length=255, verbose_name='项目')
|
||||
model = models.CharField(max_length=255, verbose_name='型号')
|
||||
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='参考单价')
|
||||
procurement_method = models.CharField(max_length=50, choices=EquipmentBudget.BUDGET_TYPES, verbose_name='采购方式')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.project} - {self.model}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = '模板设备项'
|
||||
verbose_name_plural = '模板设备项'
|
||||
|
||||
|
||||
class TemplateInfrastructureItem(models.Model):
|
||||
"""模板基础设施项"""
|
||||
template = models.ForeignKey(BudgetTemplate, related_name='infrastructure_items', on_delete=models.CASCADE, verbose_name='模板')
|
||||
name = models.CharField(max_length=255, verbose_name='名称')
|
||||
remarks = models.TextField(blank=True, verbose_name='备注')
|
||||
unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='参考单价')
|
||||
unit = models.CharField(max_length=20, verbose_name='单位')
|
||||
description = models.TextField(blank=True, verbose_name='说明')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '模板基础设施项'
|
||||
verbose_name_plural = '模板基础设施项'
|
||||
|
||||
Reference in New Issue
Block a user