Sync DATA_MODEL_PROPERTY.md field-level Chinese annotations to Django models across 23 property tables. Adds verbose_name= and help_text= to every field in core.py, follow_keys.py, listings.py, media.py. Pre-existing partitioned-table docstrings on FollowLog/PropertyPhoto retained (signal Django ORM treats parent as unmanaged, RunSQL managed).
375 lines
12 KiB
Python
375 lines
12 KiB
Python
from django.db import models
|
||
|
||
from core.enums import (
|
||
PropertyAttachmentCategory,
|
||
PropertyFieldSurveyStatus,
|
||
PropertyPhotoCategory,
|
||
PropertySurveyPhotoCategory,
|
||
)
|
||
from core.models.base import UUIDPrimaryKeyModel
|
||
|
||
|
||
class FieldSurvey(UUIDPrimaryKeyModel):
|
||
property = models.ForeignKey(
|
||
"fonrey_property.Property",
|
||
on_delete=models.CASCADE,
|
||
related_name="field_surveys",
|
||
verbose_name="所属房源",
|
||
)
|
||
status = models.CharField(
|
||
max_length=10,
|
||
choices=PropertyFieldSurveyStatus.choices,
|
||
default=PropertyFieldSurveyStatus.DRAFT,
|
||
verbose_name="实勘状态",
|
||
help_text="draft=草稿(未提交)/submitted=已提交(已完成)",
|
||
)
|
||
|
||
gps_latitude = models.DecimalField(
|
||
max_digits=10,
|
||
decimal_places=7,
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="GPS 纬度",
|
||
help_text="实勘打卡位置;精度 7 位小数",
|
||
)
|
||
gps_longitude = models.DecimalField(
|
||
max_digits=10,
|
||
decimal_places=7,
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="GPS 经度",
|
||
help_text="实勘打卡位置;精度 7 位小数",
|
||
)
|
||
gps_accuracy = models.DecimalField(
|
||
max_digits=6,
|
||
decimal_places=2,
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="GPS 精度",
|
||
help_text="米;标注定位误差",
|
||
)
|
||
|
||
description = models.TextField(
|
||
blank=True,
|
||
default="",
|
||
verbose_name="实勘说明",
|
||
help_text="最多 200 字;经纪人现场情况描述",
|
||
)
|
||
|
||
submitted_at = models.DateTimeField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="提交时间",
|
||
help_text="status 变为 submitted 时记录;NULL=尚未提交",
|
||
)
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
||
updated_at = models.DateTimeField(auto_now=True, verbose_name="最后更新时间")
|
||
created_by = models.ForeignKey(
|
||
"org.Staff",
|
||
on_delete=models.RESTRICT,
|
||
verbose_name="实勘人",
|
||
help_text="禁止置 NULL 保留审计",
|
||
)
|
||
|
||
class Meta:
|
||
db_table = "field_surveys"
|
||
verbose_name = "实勘记录"
|
||
verbose_name_plural = "实勘记录"
|
||
indexes = [
|
||
models.Index(fields=["property"], name="idx_fs_property"),
|
||
models.Index(fields=["property", "status"], name="idx_fs_submitted"),
|
||
]
|
||
|
||
|
||
class SurveyPhoto(UUIDPrimaryKeyModel):
|
||
survey = models.ForeignKey(
|
||
FieldSurvey,
|
||
on_delete=models.CASCADE,
|
||
related_name="photos",
|
||
verbose_name="所属实勘",
|
||
help_text="实勘删除时联级删除",
|
||
)
|
||
category = models.CharField(
|
||
max_length=20,
|
||
choices=PropertySurveyPhotoCategory.choices,
|
||
verbose_name="照片空间分类",
|
||
help_text="layout=户型图/living_room=客厅/dining_room=餐厅/bedroom=卧室/bathroom=卫生间/kitchen=厨房/entrance=门厅/balcony=阳台/study=书房/indoor_other=室内其他/outdoor=外景",
|
||
)
|
||
file_key = models.TextField(
|
||
verbose_name="原图存储路径",
|
||
help_text="Cloudflare R2 对象路径",
|
||
)
|
||
thumbnail_key = models.TextField(
|
||
blank=True,
|
||
default="",
|
||
verbose_name="缩略图路径",
|
||
help_text="Cloudflare Images 自动生成",
|
||
)
|
||
file_size = models.IntegerField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="文件大小",
|
||
help_text="bytes",
|
||
)
|
||
width = models.IntegerField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="图片宽度",
|
||
help_text="像素;上传时解析",
|
||
)
|
||
height = models.IntegerField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="图片高度",
|
||
help_text="像素;上传时解析",
|
||
)
|
||
sort_order = models.SmallIntegerField(
|
||
default=0,
|
||
verbose_name="排序权重",
|
||
help_text="同一空间分类内,数值越小越靠前",
|
||
)
|
||
is_vr_screenshot = models.BooleanField(
|
||
default=False,
|
||
verbose_name="是否为VR截图",
|
||
help_text="true=全景/VR截图(区别于普通实拍照片)",
|
||
)
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
|
||
|
||
class Meta:
|
||
db_table = "survey_photos"
|
||
verbose_name = "实勘照片"
|
||
verbose_name_plural = "实勘照片"
|
||
indexes = [
|
||
models.Index(fields=["survey"], name="idx_sp_survey"),
|
||
models.Index(fields=["survey", "category"], name="idx_sp_category"),
|
||
]
|
||
|
||
|
||
class PropertyPhoto(models.Model):
|
||
"""Partitioned table (PARTITION BY RANGE created_at).
|
||
|
||
Managed via RunSQL; Django ORM treats parent as unmanaged.
|
||
"""
|
||
|
||
id = models.UUIDField(primary_key=True, verbose_name="主键")
|
||
created_at = models.DateTimeField(
|
||
verbose_name="上传时间",
|
||
help_text="分区键;系统自动",
|
||
)
|
||
property = models.ForeignKey(
|
||
"fonrey_property.Property",
|
||
on_delete=models.CASCADE,
|
||
related_name="photos",
|
||
verbose_name="所属房源",
|
||
)
|
||
|
||
category = models.CharField(
|
||
max_length=20,
|
||
choices=PropertyPhotoCategory.choices,
|
||
verbose_name="照片分类",
|
||
help_text="cover=封面/entrance=门厅/living_room=客厅/dining_room=餐厅/bedroom=卧室/bathroom=卫生间/kitchen=厨房/balcony=阳台/study=书房/indoor_other=室内其他/outdoor=外景/panorama=全景",
|
||
)
|
||
file_key = models.TextField(
|
||
verbose_name="原图存储路径",
|
||
help_text="Cloudflare R2/S3 对象路径",
|
||
)
|
||
thumbnail_key = models.TextField(
|
||
blank=True,
|
||
default="",
|
||
verbose_name="缩略图路径",
|
||
help_text="Cloudflare Images 自动生成",
|
||
)
|
||
file_name = models.CharField(
|
||
max_length=255,
|
||
blank=True,
|
||
default="",
|
||
verbose_name="原始文件名",
|
||
)
|
||
file_size = models.IntegerField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="文件大小",
|
||
help_text="bytes",
|
||
)
|
||
width = models.IntegerField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="图片宽度",
|
||
help_text="像素;上传时解析",
|
||
)
|
||
height = models.IntegerField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="图片高度",
|
||
help_text="像素;上传时解析",
|
||
)
|
||
|
||
is_cover = models.BooleanField(
|
||
default=False,
|
||
verbose_name="是否为封面图",
|
||
help_text="true=封面;每套房源只能有一张封面(唯一约束保证)",
|
||
)
|
||
sort_order = models.SmallIntegerField(
|
||
default=0,
|
||
verbose_name="排序权重",
|
||
help_text="同一房源内,数值越小越靠前",
|
||
)
|
||
|
||
updated_at = models.DateTimeField(auto_now=True, verbose_name="最后更新时间")
|
||
created_by = models.ForeignKey(
|
||
"org.Staff",
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
verbose_name="上传人",
|
||
)
|
||
|
||
class Meta:
|
||
db_table = "property_photos"
|
||
verbose_name = "房源图片"
|
||
verbose_name_plural = "房源图片"
|
||
managed = False
|
||
unique_together = (("id", "created_at"),)
|
||
|
||
|
||
class PropertyAttachment(UUIDPrimaryKeyModel):
|
||
property = models.ForeignKey(
|
||
"fonrey_property.Property",
|
||
on_delete=models.CASCADE,
|
||
related_name="attachments",
|
||
verbose_name="所属房源",
|
||
)
|
||
category = models.CharField(
|
||
max_length=20,
|
||
choices=PropertyAttachmentCategory.choices,
|
||
default=PropertyAttachmentCategory.OTHER,
|
||
verbose_name="附件分类",
|
||
help_text="id_card=身份证/property_cert=产权证书/commission_letter=委托书/other=其他材料",
|
||
)
|
||
file_key = models.TextField(
|
||
verbose_name="附件存储路径",
|
||
help_text="Cloudflare R2 对象路径",
|
||
)
|
||
file_name = models.CharField(max_length=255, verbose_name="原始文件名")
|
||
file_size = models.IntegerField(
|
||
verbose_name="文件大小",
|
||
help_text="bytes",
|
||
)
|
||
file_type = models.CharField(
|
||
max_length=50,
|
||
blank=True,
|
||
default="",
|
||
verbose_name="MIME 类型",
|
||
help_text="如 application/pdf、image/jpeg",
|
||
)
|
||
sort_order = models.SmallIntegerField(
|
||
default=0,
|
||
verbose_name="排序权重",
|
||
help_text="控制同一房源附件的显示顺序",
|
||
)
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
|
||
created_by = models.ForeignKey(
|
||
"org.Staff",
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
verbose_name="上传人",
|
||
)
|
||
|
||
class Meta:
|
||
db_table = "property_attachments"
|
||
verbose_name = "房源附件"
|
||
verbose_name_plural = "房源附件"
|
||
indexes = [
|
||
models.Index(fields=["property"], name="idx_pa_property"),
|
||
models.Index(fields=["property", "category"], name="idx_pa_category"),
|
||
]
|
||
|
||
|
||
class PropertyTag(UUIDPrimaryKeyModel):
|
||
name = models.CharField(
|
||
max_length=50,
|
||
verbose_name="标签名称",
|
||
help_text="最多 50 字;如:学区/地铁口/满五唯一",
|
||
)
|
||
color = models.CharField(
|
||
max_length=7,
|
||
blank=True,
|
||
default="",
|
||
verbose_name="显示颜色",
|
||
help_text="HEX 色值,如 #FF5733;前端标签徽章颜色",
|
||
)
|
||
is_system = models.BooleanField(
|
||
default=False,
|
||
verbose_name="是否系统预置",
|
||
help_text="true=系统内置标签不可删除;false=运营自定义标签可删",
|
||
)
|
||
sort_order = models.IntegerField(
|
||
default=0,
|
||
verbose_name="排序权重",
|
||
help_text="数值越小越靠前",
|
||
)
|
||
is_active = models.BooleanField(
|
||
default=True,
|
||
verbose_name="是否启用",
|
||
help_text="false=已停用不再展示",
|
||
)
|
||
|
||
class Meta:
|
||
db_table = "property_tags"
|
||
verbose_name = "房源标签"
|
||
verbose_name_plural = "房源标签"
|
||
|
||
|
||
class PropertyTagRelation(models.Model):
|
||
property = models.ForeignKey(
|
||
"fonrey_property.Property",
|
||
on_delete=models.CASCADE,
|
||
related_name="tag_relations",
|
||
verbose_name="所属房源",
|
||
)
|
||
tag = models.ForeignKey(
|
||
PropertyTag,
|
||
on_delete=models.CASCADE,
|
||
related_name="property_relations",
|
||
verbose_name="所属标签",
|
||
)
|
||
|
||
class Meta:
|
||
db_table = "property_tag_relations"
|
||
verbose_name = "房源标签关联"
|
||
verbose_name_plural = "房源标签关联"
|
||
constraints = [
|
||
models.UniqueConstraint(fields=["property", "tag"], name="uq_ptr_property_tag"),
|
||
]
|
||
indexes = [
|
||
models.Index(fields=["property"], name="idx_ptr_property"),
|
||
models.Index(fields=["tag"], name="idx_ptr_tag"),
|
||
]
|
||
|
||
|
||
class PropertyFavorite(models.Model):
|
||
staff = models.ForeignKey(
|
||
"org.Staff",
|
||
on_delete=models.CASCADE,
|
||
related_name="favorite_properties",
|
||
verbose_name="收藏人",
|
||
help_text="员工注销时删除收藏记录",
|
||
)
|
||
property = models.ForeignKey(
|
||
"fonrey_property.Property",
|
||
on_delete=models.CASCADE,
|
||
related_name="favorited_by",
|
||
verbose_name="收藏的房源",
|
||
)
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="收藏时间")
|
||
|
||
class Meta:
|
||
db_table = "property_favorites"
|
||
verbose_name = "房源收藏"
|
||
verbose_name_plural = "房源收藏"
|
||
constraints = [
|
||
models.UniqueConstraint(fields=["staff", "property"], name="uq_pfav_staff_property"),
|
||
]
|
||
indexes = [models.Index(fields=["staff"], name="idx_pfav_staff")]
|