models.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. from django.db import models
  2. from django.contrib.auth import get_user_model
  3. User = get_user_model()
  4. from django.db import models
  5. from django.db import models
  6. from api.models import UserInfo
  7. class City(models.Model):
  8. name = models.CharField(max_length=50, verbose_name="城市名称")
  9. code = models.CharField(max_length=20, unique=True, verbose_name="城市代码")
  10. description = models.TextField(verbose_name="城市描述", blank=True)
  11. image = models.ImageField(upload_to='cities/', verbose_name="城市图片", null=True, blank=True)
  12. is_hot = models.BooleanField(default=False, verbose_name="是否热门")
  13. # 新增的经纬度字段
  14. latitude = models.DecimalField(
  15. max_digits=9,
  16. decimal_places=6,
  17. verbose_name="纬度",
  18. null=True,
  19. blank=True,
  20. help_text="例如:北京的纬度是39.9042"
  21. )
  22. longitude = models.DecimalField(
  23. max_digits=9,
  24. decimal_places=6,
  25. verbose_name="经度",
  26. null=True,
  27. blank=True,
  28. help_text="例如:北京的经度是116.4074"
  29. )
  30. created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
  31. updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
  32. class Meta:
  33. verbose_name = "城市"
  34. verbose_name_plural = "城市"
  35. def __str__(self):
  36. return self.name
  37. class Attraction(models.Model):
  38. city = models.ForeignKey(City, on_delete=models.CASCADE, related_name='attractions')
  39. name = models.CharField(max_length=100, verbose_name="景点名称")
  40. description = models.TextField(verbose_name="景点描述")
  41. history_significance = models.TextField(verbose_name="历史意义", blank=True)
  42. learning_point = models.TextField(verbose_name="学习要点", blank=True)
  43. short_desc = models.CharField(max_length=200, verbose_name="简短描述", blank=True)
  44. address = models.CharField(max_length=200, verbose_name="地址")
  45. latitude = models.FloatField(verbose_name="纬度", null=True, blank=True)
  46. longitude = models.FloatField(verbose_name="经度", null=True, blank=True)
  47. ticket_price = models.DecimalField(
  48. max_digits=8,
  49. decimal_places=2,
  50. verbose_name="门票价格",
  51. default=0
  52. )
  53. ticket_info = models.CharField(
  54. max_length=100,
  55. verbose_name="门票信息",
  56. blank=True,
  57. default="凭身份证免费参观"
  58. )
  59. open_hours = models.CharField(max_length=100, verbose_name="开放时间", blank=True)
  60. image = models.ImageField(
  61. upload_to='attractions/',
  62. verbose_name="景点图片",
  63. null=True,
  64. blank=True
  65. )
  66. tags = models.JSONField(default=list, verbose_name="标签")
  67. history = models.TextField(verbose_name="历史背景", blank=True)
  68. is_featured = models.BooleanField(default=False, verbose_name="是否特色")
  69. created_at = models.DateTimeField(auto_now_add=True)
  70. updated_at = models.DateTimeField(auto_now=True)
  71. class Meta:
  72. verbose_name = "景点"
  73. verbose_name_plural = "景点"
  74. def __str__(self):
  75. return f"{self.name} ({self.city.name})"
  76. class RedTourismPlan(models.Model):
  77. # 行程状态选项
  78. STATUS_CHOICES = (
  79. ('in_progress', '进行中'),
  80. ('completed', '已完成'),
  81. )
  82. user = models.ForeignKey(
  83. UserInfo,
  84. on_delete=models.CASCADE,
  85. related_name='red_tourism_plans',
  86. verbose_name='关联用户',
  87. null=True,
  88. blank=True
  89. )
  90. # 新增状态字段
  91. status = models.CharField(
  92. max_length=20,
  93. choices=STATUS_CHOICES,
  94. default='in_progress',
  95. verbose_name='行程状态'
  96. )
  97. # 其他字段保持不变...
  98. cities = models.ManyToManyField(
  99. City,
  100. related_name='red_tourism_plans',
  101. verbose_name='关联城市'
  102. )
  103. title = models.CharField(max_length=200, verbose_name='行程标题')
  104. description = models.TextField(verbose_name='行程描述')
  105. days = models.PositiveIntegerField(verbose_name='天数')
  106. created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
  107. last_updated = models.DateTimeField(auto_now=True, verbose_name='最后更新时间')
  108. is_red_tourism = models.BooleanField(default=True, verbose_name='是否红色旅游')
  109. statistics = models.JSONField(default=dict, verbose_name='统计数据')
  110. education_goals = models.JSONField(default=list, verbose_name='教育目标')
  111. original_data = models.JSONField(default=dict, verbose_name='原始数据')
  112. class Meta:
  113. verbose_name = '红色旅游行程'
  114. verbose_name_plural = verbose_name
  115. ordering = ['-created_at']
  116. def __str__(self):
  117. return f"{self.title} (用户: {self.user.phone})"
  118. class RedTourismDayPlan(models.Model):
  119. plan = models.ForeignKey(
  120. RedTourismPlan,
  121. on_delete=models.CASCADE,
  122. related_name='day_plans',
  123. verbose_name='所属行程',
  124. null=True,
  125. blank=True
  126. )
  127. day_number = models.PositiveIntegerField(verbose_name='第几天')
  128. theme = models.CharField(max_length=100, verbose_name='当日主题')
  129. summary = models.TextField(blank=True, verbose_name='当日总结')
  130. transport = models.CharField(max_length=50, verbose_name='交通方式')
  131. travel_tips = models.JSONField(default=list, verbose_name='旅行提示')
  132. class Meta:
  133. verbose_name = '红色旅游每日行程'
  134. verbose_name_plural = verbose_name
  135. ordering = ['plan', 'day_number']
  136. unique_together = ('plan', 'day_number')
  137. def __str__(self):
  138. return f"{self.plan.title} - 第{self.day_number}天"
  139. class RedTourismSpot(models.Model):
  140. day_plan = models.ForeignKey(
  141. RedTourismDayPlan,
  142. on_delete=models.CASCADE,
  143. related_name='spots',
  144. verbose_name='所属日计划',
  145. null=True,
  146. blank=True
  147. )
  148. spot_id = models.CharField(max_length=50, verbose_name='景点ID')
  149. name = models.CharField(max_length=100, verbose_name='景点名称')
  150. description = models.TextField(verbose_name='景点描述')
  151. address = models.CharField(max_length=200, verbose_name='地址')
  152. open_hours = models.CharField(max_length=50, verbose_name='开放时间')
  153. ticket_info = models.CharField(max_length=100, verbose_name='门票信息')
  154. history_significance = models.TextField(verbose_name='历史意义')
  155. image = models.URLField(max_length=500, verbose_name='图片URL')
  156. latitude = models.FloatField(verbose_name='纬度')
  157. longitude = models.FloatField(verbose_name='经度')
  158. visit_time = models.CharField(max_length=50, verbose_name='参观时间')
  159. duration = models.PositiveIntegerField(verbose_name='参观时长(分钟)')
  160. order = models.PositiveIntegerField(verbose_name='排序')
  161. visiting_etiquette = models.JSONField(default=list, verbose_name='参观礼仪')
  162. is_red_tourism = models.BooleanField(default=True, verbose_name='是否红色景点')
  163. has_checked = models.BooleanField(default=False, verbose_name='是否已打卡')
  164. class Meta:
  165. verbose_name = '红色旅游景点'
  166. verbose_name_plural = verbose_name
  167. ordering = ['day_plan', 'order']
  168. def __str__(self):
  169. return f"{self.name} (第{self.day_plan.day_number}天)"
  170. # models.py
  171. class UserCheckIn(models.Model):
  172. """用户打卡记录模型"""
  173. user = models.ForeignKey(
  174. User,
  175. on_delete=models.CASCADE,
  176. verbose_name='用户'
  177. )
  178. spot = models.ForeignKey(
  179. 'RedTourismSpot',
  180. on_delete=models.CASCADE,
  181. verbose_name='景点'
  182. )
  183. plan = models.ForeignKey(
  184. 'RedTourismPlan',
  185. on_delete=models.CASCADE,
  186. verbose_name='行程'
  187. )
  188. check_in_time = models.DateTimeField(
  189. auto_now_add=True,
  190. verbose_name='打卡时间'
  191. )
  192. image_url = models.URLField(
  193. max_length=500,
  194. blank=True,
  195. verbose_name='打卡图片URL'
  196. )
  197. note = models.TextField(
  198. blank=True,
  199. verbose_name='打卡文案',
  200. default=''
  201. )
  202. location = models.JSONField(
  203. default=dict,
  204. verbose_name='位置信息'
  205. )
  206. class Meta:
  207. verbose_name = '用户打卡记录'
  208. verbose_name_plural = verbose_name
  209. unique_together = ('user', 'spot') # 防止重复打卡
  210. def __str__(self):
  211. return f"{self.user.username}于{self.check_in_time}打卡{self.spot.name}"