我的 django 模型 DateField 如何将 30 天添加到提供的值?

Posted

技术标签:

【中文标题】我的 django 模型 DateField 如何将 30 天添加到提供的值?【英文标题】:How can my django model DateField add 30 days to the provided value? 【发布时间】:2011-01-13 00:42:54 【问题描述】:

正如标题所示。我想在 DateField 字段中添加 30 天。这是使用auto_now_add=True创建记录时自动填充的

任何想法如何去做?

谢谢

【问题讨论】:

这是一个猜测,但 Django 表单允许在其 initial= 值中调用函数。如果模型也是这种情况,那么您可以删除 auto_add_now 并将其替换为 default=lambda: datetime.now()+timedelta(days=30) 【参考方案1】:

使用 Python timedelta:

from datetime import timedelta
d = timedelta(days=30)

# object is your current instance of the model
object.yourdatefield += d
# or this because I am not sure whether the previous works
object.yourdatefield = object.yourdatefield + d

object.save()

来自Django documentation:

日期字段 日期,在 Python 中由 datetime.date 实例表示。

如果您想在创建对象时增加 30 天,请忘记 auto_now_add=True 并按照 becomeGuru 的建议进行操作。有关覆盖save() 的信息也可以在Django documentation 中找到。

【讨论】:

【参考方案2】:

覆盖模型上的保存,并在保存时检查 pk 是否已填充。

>>> from datetime import datetime
>>> from datetime import timedelta
>>> cur_date = datetime.now()
>>> cur_date
datetime.datetime(2010, 2, 4, 5, 0, 24, 437405)
>>> cur_date+timedelta(days=30)
datetime.datetime(2010, 3, 6, 5, 0, 24, 437405)

【讨论】:

【参考方案3】:

// 更新

原帖下的评论让我思考。我想这是迄今为止最好的解决方案:

from datetime import datetime, timedelta

class MyModel(models.Model):
   mydate = models.DateTimeField(default=datetime.now()+timedelta(days=30))

// 2. 更新

如果你想定义一个模型属性来保存应该添加的天数,你将需要覆盖 save 方法。到目前为止,我想不出更简单的方法。

解决方案:

class MyModel(models.Model):
  mydate = models.DateTimeField(editable=False)
  daysadded = models.IntegerField()

  def save(self):
    from datetime import datetime, timedelta
    d = timedelta(days=self.daysadded)

    if not self.id:
      self.mydate = datetime.now() + d
      super(MyModel, self).save()

作为 BeingGuru 已经建议您应该覆盖您的模型保存方法。

示例:

class MyModel(models.Model):
  mydate = models.DateTimeField(auto_now_add=True)      

  def save(self):
    from datetime import timedelta
    d = timedelta(days=30)

    // only add 30 days if it's the first time the model is saved
    if not self.id:
      // not saving the model before adding the timedelta gave me errors 
      super(MyModel, self).save()

      self.mydate += d

      // final save
      super(MyModel, self).save()

这对我来说不是最好的方法,因为您必须保存模型两次。但是使用 auto_now_add 需要您在创建 mydate 的日期时间实例之前先保存模型。

另一种只需要保存一次的方法:

class MyModel(models.Model):
  mydate = models.DateTimeField(editable=False) // editable=False to hide in admin

  def save(self):
    from datetime import datetime, timedelta
    d = timedelta(days=30)

    // only add 30 days if it's the first time the model is saved
    if not self.id:
      self.mydate = datetime.now() + d
      super(MyModel, self).save()

希望有所帮助!

【讨论】:

更新:按预期工作,但是 30 天将是一个变量。可能是 30 天、60 天、90 天等。有什么想法吗?我应该添加一个'expires_in'字段来保存它过期的天数吗?我如何使用这个新的“expires_in”字段来编辑“timedelta(days=30)”行? 我理解正确吗?您想要另一个模型字段,其中包含一个描述要添加多少天的值? 我可能错了,但我认为您的第一个解决方案(使用default=datetime.now()+timedelta(days=30))是错误的。该模块在服务器启动时加载一次,因此datetime.now()仅在服务器启动时执行(而不是在添加新实例时)。 答案的第一部分不正确。您必须传递像@Simanas 回答状态这样的可调用对象,否则您将无法获得所需的内容。 @FelixKling 是对的,将DateTimeField 的默认值设置为带有datetime.now() 的任何值是完全错误的;该函数将与类定义同时进行评估,因此不仅在每次服务器启动时默认更改,而且每当您运行makemigrations时都会更改;实际上,您可以根据需要多次运行它,并且每次都会检测到对该字段的“更改”。【参考方案4】:

无需实现自定义保存方法。

同样这样做default=datetime.now()+timedelta(days=30) 是绝对错误的! 当您启动 django 实例时,它会被评估。如果您使用 apache,它可能会起作用,因为在某些配置中,apache 会在每个请求上撤销您的 django 应用程序,但您仍然可以在某天查看您的代码并试图找出为什么计算结果不符合您的预期。

这样做的正确方法是将可调用对象传递给默认参数。它可以是 datetime.today 函数或您的自定义函数。然后每次您请求新的默认值时都会对其进行评估。

def get_deadline():
    return datetime.today() + timedelta(days=20)

class Bill(models.Model):
    name = models.CharField(max_length=50)
    customer = models.ForeignKey(User, related_name='bills')
    date = models.DateField(default=datetime.today)
    deadline = models.DateField(default=get_deadline)

【讨论】:

我经常使用这个!当您想要获取所有不超过 20 天左右的帖子时尤其有用。只需使用 `BlogPost.objects.filter(pub_date__gt=datetime.now()-timedelta(days=20)´。这会转化为 SQL,因此非常有效!Reference in django docs @mart0903 你的代码正是我所需要的:BlogPost.objects.filter(pub_date__gt=datetime.now()-timedelta(days=20) 换句话说,只有 pub_date 比 20 天前更新的对象。 default=lambda: datetime.now()+timedelta(days=30) @exshinigami 在模型字段选项中使用 lambdas 不再受支持:github.com/django/django/commit/… 这是我发现每次运行makemigrations 时都不会创建新迁移的唯一答案。感谢@Simanas 的工作解决方案。【参考方案5】:

时间增量文档: https://docs.python.org/2/library/datetime.html

def make_timedelta(seconds):
        return timedelta(days=seconds // 86399, seconds=seconds % 86399)

【讨论】:

以上是关于我的 django 模型 DateField 如何将 30 天添加到提供的值?的主要内容,如果未能解决你的问题,请参考以下文章

在 django 模型中加密 DateField?

Django 2.0 ModelForm dateField 不显示为小部件

如何在 Django DateField 中仅保留日期部分

Django 模型 DateField to_python

Django 模型:可空字段

为 Django DateField 和 Postgresql 指定默认值