【问题标题】:django set DateTimeField to server's current timedjango 将 DateTimeField 设置为服务器的当前时间
【发布时间】:2011-11-19 21:59:27
【问题描述】:

我如何在 django 中执行与此 SQL 等效的操作?

UPDATE table SET timestamp=NOW() WHERE ...

我特别想使用服务器的内置函数设置 datetime 字段,以从运行数据库的服务器获取系统时间,而不是客户端计算机上的时间。

我知道您可以直接执行原始 sql,但我正在寻找更便携的解决方案,因为数据库具有不同的功能来获取当前日期时间。

编辑:很少有人提到 auto_now 参数。这会在每次修改时更新日期时间,而我只想在某些情况下更新日期时间。

【问题讨论】:

    标签: python database django


    【解决方案1】:

    正如 j0ker 所说,如果您想要自动更新时间戳,请使用 auto_now 选项。例如。 date_modified = models.DateTimeField(auto_now=True).

    如果您只想在首次创建对象时将字段设置为现在,您应该使用:

    date_modified = models.DateTimeField(auto_now_add=True)
    

    或者如果你想手动做,不就是用pythondatetime.now()简单赋值吗?

    from datetime import datetime
    
    obj.date_modified = datetime.now()
    

    【讨论】:

    • Auto_now 在每次我不想要的更新时更新日期时间字段。而 python 的 datetime.now() 将在客户端为您提供当前的日期时间,这不能保证甚至接近服务器上的日期时间。
    • datetime.now() 将如何使用客户端的日期时间?视图中的所有 Python 代码都在服务器上执行,因此它当然使用服务器的日期时间。
    • 服务器是指托管数据库的机器,客户端是运行 python/django 并从数据库访问数据的机器。这里的用例是,当多个客户端机器访问数据库并更新时间戳时,如果客户端的系统时间没有同步(有时由于缺乏权限而无法同步),则很难弄清楚哪个顺序条目已更新 - 这就是为什么最好在服务器上使用系统时间以便时间戳来自同一个时钟。
    • 现在我明白了。您应该将其添加到您的原始问题中,因为我认为您指的不是数据库服务器。
    • 澄清一下,这不是这个问题的正确答案。请进一步查看@tvorog 的答案。
    【解决方案2】:

    创建表格时,添加数据后要在字段中设置日期的字段添加此代码到字段

    class MyModel(models.Model):
      created_at = models.DateTimeField(auto_now_add=True)
      updated_at = models.DateTimeField(auto_now=True)
    

    【讨论】:

      【解决方案3】:

      接受的答案已过时。这是目前最简单的方法:

      >>> from django.utils import timezone
      >>> timezone.now()
      datetime.datetime(2018, 12, 3, 14, 57, 11, 703055, tzinfo=<UTC>)
      

      【讨论】:

        【解决方案4】:

        你可以使用数据库函数Now启动Django 1.9:

        from django.db.models.functions import Now
        Model.objects.filter(...).update(timestamp=Now())
        

        【讨论】:

        • 根据文档,这将返回数据库服务器的时间,并且似乎与 auto_now 和其他人最一致。
        • 这是正确答案。请注意,Now() 在 PostgreSQL(可能还有其他)上转换为 statement_timestamp(),在大多数正常用例中相当于 now()(查看文档了解更多详细信息)。
        【解决方案5】:

        我已经创建了一个 Python Django 插件模块,它允许您控制 CURRENT_TIMESTAMPDateTimeField 对象上的使用,无论是在特定情况下(参见下面的 usage)还是自动用于 auto_now 和 @ 987654327@列。

        django-pg-current-timestamp

        GitHub:https://github.com/jaytaylor/django-pg-current-timestamp

        PyPi:https://pypi.python.org/pypi/django-pg-current-timestamp

        示例用法:

        from django_pg_current_timestamp import CurrentTimestamp
        
        mm = MyModel.objects.get(id=1)
        mm.last_seen_date = CurrentTimestamp()
        mm.save()
        ## Resulting SQL:
        ##     UPDATE "my_model" SET "last_seen_date" = CURRENT_TIMESTAMP;
        
        print MyModel.objects.filter(last_seen_date__lt=CURRENT_TIME).count()
        
        MyModel.objects.filter(id__in=[1, 2, 3]).update(last_seen_date=CURRENT_TIME)
        

        【讨论】:

        • 这已经过时了。
        【解决方案6】:

        我调整后的代码适用于 sqlite、mysql 和 postgresql,并且比建议的解决方案更简洁。

        class DBCurrentTimestamp:
            def __str__(self):
                return 'DATABASE CURRENT_TIMESTAMP()'
        
            def as_sql(self, qn, connection):
                return 'CURRENT_TIMESTAMP', {}
        
            @classmethod
            def patch(cls, *args):
                def create_tweaked_get_db_prep_value(orig_get_db_prep_value):
                    def get_db_prep_value(self, value, connection, prepared=False):
                        return value if isinstance(value, cls) else orig_get_db_prep_value(self, value, connection, prepared)
        
                    return get_db_prep_value
        
                for field_class in args:
                    field_class.get_db_prep_value = create_tweaked_get_db_prep_value(field_class.get_db_prep_value)
        

        我在我的 models.py 文件的末尾激活它,如下所示:

        DBCurrentTimestamp.patch(models.DateField, models.TimeField, models.DateTimeField)
        

        并像这样使用它:

        self.last_pageview = DBCurrentTimestamp()
        

        【讨论】:

          【解决方案7】:

          这是我解决此问题的方法。希望它可以节省一些时间:

          from django.db import models
          
          class DBNow(object):
              def __str__(self):
                  return 'DATABASE NOW()'
              def as_sql(self, qn, val):
                  return 'NOW()', {}
              @classmethod
              def patch(cls, field):
                  orig_prep_db = field.get_db_prep_value
                  orig_prep_lookup = field.get_prep_lookup
                  orig_db_prep_lookup = field.get_db_prep_lookup
          
                  def prep_db_value(self, value, connection, prepared=False):
                      return value if isinstance(value, cls) else orig_prep_db(self, value, connection, prepared)
          
                  def prep_lookup(self, lookup_type, value):
                      return value if isinstance(value, cls) else orig_prep_lookup(self, lookup_type, value)
          
                  def prep_db_lookup(self, lookup_type, value, connection, prepared=True):
                      return value if isinstance(value, cls) else orig_db_prep_lookup(self, lookup_type, value, connection=connection, prepared=True)
          
                  field.get_db_prep_value = prep_db_value
                  field.get_prep_lookup = prep_lookup
                  field.get_db_prep_lookup = prep_db_lookup
          
          # DBNow Activator
          DBNow.patch(models.DateTimeField)
          

          然后只使用 DBNow() 作为需要更新和过滤的值:

          books = Book.objects.filter(created_on__gt=DBNow())
          
              or:
          
          book.created_on = DBNow()
          book.save()
          

          【讨论】:

          • 我可以知道你的 Django 版本吗?我在 Django 1.6 上将示例与我的项目一起使用,但它不起作用,因为 Django 将使用 str 的返回值而不是 as_sql 的返回值来构造 SQL。
          【解决方案8】:

          你可以使用类似这样的东西来创建一个自定义值来表示对数据库当前时间的使用:

          class DatabaseDependentValue(object):
              def setEngine(self, engine):
                  self.engine = engine
          
              @staticmethod
              def Converter(value, *args, **kwargs):
                  return str(value)
          
          class DatabaseNow(DatabaseDependentValue):
              def __str__(self):
                  if self.engine == 'django.db.backends.mysql':
                      return 'NOW()'
                  elif self.engine == 'django.db.backends.postgresql':
                      return 'current_timestamp'
                  else:
                      raise Exception('Unimplemented for engine ' + self.engine)
          
          django_conversions.update({DatabaseNow: DatabaseDependentValue.Converter})
          
          def databaseDependentPatch(cls):
              originalGetDbPrepValue = cls.get_db_prep_value
              def patchedGetDbPrepValue(self, value, connection, prepared=False):
                  if isinstance(value, DatabaseDependentValue):
                      value.setEngine(connection.settings_dict['ENGINE'])
                      return value
                  return originalGetDbPrepValue(self, value, connection, prepared)
              cls.get_db_prep_value = patchedGetDbPrepValue
          

          然后能够在 DateTimeField 上使用 DatabaseNow:

          databaseDependentPatch(models.DateTimeField)
          

          这反过来又最终让你做得又好又干净:

          class Operation(models.Model):
              dateTimeCompleted = models.DateTimeField(null=True)
              # ...
          
          operation = # Some previous operation
          operation.dateTimeCompleted = DatabaseNow()
          operation.save()
          

          【讨论】:

          • 事实证明,对我来说,django_conversions.update 是使它工作的必要条件,而其他一些答案中却没有。我正在使用 Django 1.6。
          【解决方案9】:

          如果您想要来自外部服务器的日期时间(即,不是托管 Django 应用程序的服务器),您将不得不手动将其固定以使用数据时间。您可以使用 SQL 命令,例如 select now(); 或通过 SSH 的命令,例如 ssh user@host "date +%s"

          【讨论】:

          • 这比直接执行原始更新sql更复杂(问题中提到了)
          • 我的印象是您希望 Django 在表单上显示 sql server 的时间 - 您只是希望 sql server 在插入/更新期间设置它自己的时间吗?
          【解决方案10】:

          也许你应该看看文档:
          Modelfields: DateField

          “auto_now”选项可能正是您要搜索的内容。您也可以将它与 DateTimeField 一起使用。每次保存模型时它都会更新 DateTime。因此,为您的 DateTimeField 设置该选项应该足以检索数据记录并再次保存以设置正确的时间。

          【讨论】:

          • 那我会推荐 jesse 的 datetime.now()-solution。
          猜你喜欢
          • 2019-05-26
          • 1970-01-01
          • 1970-01-01
          • 2017-04-01
          • 2022-08-14
          • 1970-01-01
          • 1970-01-01
          • 2014-11-12
          • 1970-01-01
          相关资源
          最近更新 更多