123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- from django.db import models
- from django.contrib.auth import get_user_model
- User = get_user_model()
- from django.db import models
- from django.db import models
- from api.models import UserInfo
- class City(models.Model):
- name = models.CharField(max_length=50, verbose_name="城市名称")
- code = models.CharField(max_length=20, unique=True, verbose_name="城市代码")
- description = models.TextField(verbose_name="城市描述", blank=True)
- image = models.ImageField(upload_to='cities/', verbose_name="城市图片", null=True, blank=True)
- is_hot = models.BooleanField(default=False, verbose_name="是否热门")
- # 新增的经纬度字段
- latitude = models.DecimalField(
- max_digits=9,
- decimal_places=6,
- verbose_name="纬度",
- null=True,
- blank=True,
- help_text="例如:北京的纬度是39.9042"
- )
- longitude = models.DecimalField(
- max_digits=9,
- decimal_places=6,
- verbose_name="经度",
- null=True,
- blank=True,
- help_text="例如:北京的经度是116.4074"
- )
- created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
- updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
- class Meta:
- verbose_name = "城市"
- verbose_name_plural = "城市"
- def __str__(self):
- return self.name
- class Attraction(models.Model):
- city = models.ForeignKey(City, on_delete=models.CASCADE, related_name='attractions')
- name = models.CharField(max_length=100, verbose_name="景点名称")
- description = models.TextField(verbose_name="景点描述")
- history_significance = models.TextField(verbose_name="历史意义", blank=True)
- learning_point = models.TextField(verbose_name="学习要点", blank=True)
- short_desc = models.CharField(max_length=200, verbose_name="简短描述", blank=True)
- address = models.CharField(max_length=200, verbose_name="地址")
- latitude = models.FloatField(verbose_name="纬度", null=True, blank=True)
- longitude = models.FloatField(verbose_name="经度", null=True, blank=True)
- ticket_price = models.DecimalField(
- max_digits=8,
- decimal_places=2,
- verbose_name="门票价格",
- default=0
- )
- ticket_info = models.CharField(
- max_length=100,
- verbose_name="门票信息",
- blank=True,
- default="凭身份证免费参观"
- )
- open_hours = models.CharField(max_length=100, verbose_name="开放时间", blank=True)
- image = models.ImageField(
- upload_to='attractions/',
- verbose_name="景点图片",
- null=True,
- blank=True
- )
- tags = models.JSONField(default=list, verbose_name="标签")
- history = models.TextField(verbose_name="历史背景", blank=True)
- is_featured = models.BooleanField(default=False, verbose_name="是否特色")
- created_at = models.DateTimeField(auto_now_add=True)
- updated_at = models.DateTimeField(auto_now=True)
- class Meta:
- verbose_name = "景点"
- verbose_name_plural = "景点"
- def __str__(self):
- return f"{self.name} ({self.city.name})"
- class RedTourismPlan(models.Model):
- # 行程状态选项
- STATUS_CHOICES = (
- ('in_progress', '进行中'),
- ('completed', '已完成'),
- )
- user = models.ForeignKey(
- UserInfo,
- on_delete=models.CASCADE,
- related_name='red_tourism_plans',
- verbose_name='关联用户',
- null=True,
- blank=True
- )
- # 新增状态字段
- status = models.CharField(
- max_length=20,
- choices=STATUS_CHOICES,
- default='in_progress',
- verbose_name='行程状态'
- )
- # 其他字段保持不变...
- cities = models.ManyToManyField(
- City,
- related_name='red_tourism_plans',
- verbose_name='关联城市'
- )
- title = models.CharField(max_length=200, verbose_name='行程标题')
- description = models.TextField(verbose_name='行程描述')
- days = models.PositiveIntegerField(verbose_name='天数')
- created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
- last_updated = models.DateTimeField(auto_now=True, verbose_name='最后更新时间')
- is_red_tourism = models.BooleanField(default=True, verbose_name='是否红色旅游')
- statistics = models.JSONField(default=dict, verbose_name='统计数据')
- education_goals = models.JSONField(default=list, verbose_name='教育目标')
- original_data = models.JSONField(default=dict, verbose_name='原始数据')
- class Meta:
- verbose_name = '红色旅游行程'
- verbose_name_plural = verbose_name
- ordering = ['-created_at']
- def __str__(self):
- return f"{self.title} (用户: {self.user.phone})"
- class RedTourismDayPlan(models.Model):
- plan = models.ForeignKey(
- RedTourismPlan,
- on_delete=models.CASCADE,
- related_name='day_plans',
- verbose_name='所属行程',
- null=True,
- blank=True
- )
- day_number = models.PositiveIntegerField(verbose_name='第几天')
- theme = models.CharField(max_length=100, verbose_name='当日主题')
- summary = models.TextField(blank=True, verbose_name='当日总结')
- transport = models.CharField(max_length=50, verbose_name='交通方式')
- travel_tips = models.JSONField(default=list, verbose_name='旅行提示')
- class Meta:
- verbose_name = '红色旅游每日行程'
- verbose_name_plural = verbose_name
- ordering = ['plan', 'day_number']
- unique_together = ('plan', 'day_number')
- def __str__(self):
- return f"{self.plan.title} - 第{self.day_number}天"
- class RedTourismSpot(models.Model):
- day_plan = models.ForeignKey(
- RedTourismDayPlan,
- on_delete=models.CASCADE,
- related_name='spots',
- verbose_name='所属日计划',
- null=True,
- blank=True
- )
- spot_id = models.CharField(max_length=50, verbose_name='景点ID')
- name = models.CharField(max_length=100, verbose_name='景点名称')
- description = models.TextField(verbose_name='景点描述')
- address = models.CharField(max_length=200, verbose_name='地址')
- open_hours = models.CharField(max_length=50, verbose_name='开放时间')
- ticket_info = models.CharField(max_length=100, verbose_name='门票信息')
- history_significance = models.TextField(verbose_name='历史意义')
- image = models.URLField(max_length=500, verbose_name='图片URL')
- latitude = models.FloatField(verbose_name='纬度')
- longitude = models.FloatField(verbose_name='经度')
- visit_time = models.CharField(max_length=50, verbose_name='参观时间')
- duration = models.PositiveIntegerField(verbose_name='参观时长(分钟)')
- order = models.PositiveIntegerField(verbose_name='排序')
- visiting_etiquette = models.JSONField(default=list, verbose_name='参观礼仪')
- is_red_tourism = models.BooleanField(default=True, verbose_name='是否红色景点')
- has_checked = models.BooleanField(default=False, verbose_name='是否已打卡')
- class Meta:
- verbose_name = '红色旅游景点'
- verbose_name_plural = verbose_name
- ordering = ['day_plan', 'order']
- def __str__(self):
- return f"{self.name} (第{self.day_plan.day_number}天)"
- # models.py
- class UserCheckIn(models.Model):
- """用户打卡记录模型"""
- user = models.ForeignKey(
- User,
- on_delete=models.CASCADE,
- verbose_name='用户'
- )
- spot = models.ForeignKey(
- 'RedTourismSpot',
- on_delete=models.CASCADE,
- verbose_name='景点'
- )
- plan = models.ForeignKey(
- 'RedTourismPlan',
- on_delete=models.CASCADE,
- verbose_name='行程'
- )
- check_in_time = models.DateTimeField(
- auto_now_add=True,
- verbose_name='打卡时间'
- )
- image_url = models.URLField(
- max_length=500,
- blank=True,
- verbose_name='打卡图片URL'
- )
- note = models.TextField(
- blank=True,
- verbose_name='打卡文案',
- default=''
- )
- location = models.JSONField(
- default=dict,
- verbose_name='位置信息'
- )
- class Meta:
- verbose_name = '用户打卡记录'
- verbose_name_plural = verbose_name
- unique_together = ('user', 'spot') # 防止重复打卡
- def __str__(self):
- return f"{self.user.username}于{self.check_in_time}打卡{self.spot.name}"
|