Django DRF习惯跟踪器创建Tracker时批量生成对应时间段Daily实例问题
实现方案
你可以选择以下两种常用方案实现需求,根据你的业务场景二选一即可:
方案1:在TrackerSerializer的create方法中实现(优先推荐,符合DRF接口分层逻辑)
该方案仅针对通过API创建Tracker的场景自动生成Daily实例,逻辑更集中在接口层。
首先在serializers.py头部导入时间间隔工具:
from datetime import timedelta
然后修改TrackerSerializer,重写其create方法:
class TrackerSerializer(serializers.ModelSerializer): class Meta: model = Tracker fields = ['id', 'start_date', 'end_date', 'published', 'is_active', 'habit', 'user'] # 可选配置:user字段设为只读,从请求上下文自动获取,避免前端传参 # extra_kwargs = {'user': {'read_only': True}} def create(self, validated_data): # 先创建Tracker实例 tracker = Tracker.objects.create(**validated_data) current_date = tracker.start_date daily_objs = [] # 遍历整个日期区间构造Daily实例 while current_date <= tracker.end_date: daily_objs.append(Daily( date=current_date, status='TODO', tracker=tracker )) current_date += timedelta(days=1) # 批量创建提升效率,避免循环逐条插入 Daily.objects.bulk_create(daily_objs) return tracker
方案2:重写Tracker模型的save方法(全场景生效)
该方案适合需要在所有创建Tracker的场景(包括Django后台、shell操作、脚本导入等)都自动生成Daily实例的需求。
首先在models.py头部导入时间间隔工具:
from datetime import datetime, timedelta
然后修改Tracker模型,新增save方法:
class Tracker(models.Model): habit = models.ForeignKey(Habit, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) start_date = models.DateField() end_date = models.DateField() published = models.BooleanField(default=True) def is_active(self): today = datetime.now().date() return (today >= self.start_date) and (today <= self.end_date) def save(self, *args, **kwargs): # 仅新建Tracker实例时生成Daily,避免更新时重复创建 is_new_instance = self.pk is None super().save(*args, **kwargs) if is_new_instance: current_date = self.start_date daily_objs = [] while current_date <= self.end_date: daily_objs.append(Daily( date=current_date, status='TODO', tracker=self )) current_date += timedelta(days=1) Daily.objects.bulk_create(daily_objs)
可选优化
建议给Daily模型增加联合唯一约束,避免同一个Tracker下出现重复日期的Daily数据:
class Daily(models.Model): STATUS = [('DONE', 'DONE'), ('TODO', 'TODO'), ('NOTDONE', 'NOTDONE'),] date = models.DateField() status = models.CharField(choices=STATUS, max_length=10) tracker = models.ForeignKey(Tracker, on_delete=models.CASCADE) class Meta: constraints = [ models.UniqueConstraint(fields=['tracker', 'date'], name='unique_tracker_date') ]
内容的提问来源于stack exchange,提问作者Matteo Di Nome
相关产品推荐
相关产品推荐

