2011-09-19 92 views
35

如何在django中執行此SQL的等效操作?django將DateTimeField設置爲服務器的當前時間

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

特別是我想用服務器的內置函數來獲得從該數據庫上,而不是在客戶機上的時間運行服務器的系統時間設置日期時間字段。

我知道你可以直接執行原始sql,但我正在尋找一個更便攜的解決方案,因爲數據庫有不同的功能來獲取當前的日期時間。

編輯:很少人提到auto_now參數。這更新每個修改的日期時間,而我只想在某些場合更新日期時間。

回答

1

也許你應該看看到的文檔:
Modelfields: DateField

選項「auto_now」可能只是你要搜索的內容。您也可以將它與DateTimeField一起使用。每次保存模型時都會更新DateTime。因此,通過爲DateTimeField設置該選項,應該足以檢索數據記錄並再次保存以設置正確的時間。

+0

我不想在每次修改更新日期時間。 – kefeizhou

+0

然後我會推薦jesse的datetime.now() - 解決方案。 – j0ker

47

正如j0ker所說,如果要自動更新時間戳,請使用auto_now選項。例如。 date_modified = models.DateTimeField(auto_now=True)

或者如果你想手動做,是不是一個簡單的任務與Python datetime.now()

from datetime import datetime 

obj.date_modified = datetime.now() 
+3

Auto_now更新我不想要的每個更新的日期時間字段。而python的datetime.now()會在客戶端獲得當前的日期時間,並不保證它甚至接近服務器上的日期時間。 – kefeizhou

+0

datetime.now()如何使用客戶端的日期時間?視圖中的所有Python代碼都在服務器上執行,所以它當然會使用服務器的日期時間。 – j0ker

+4

服務器是指主機數據庫的機器,客戶機是運行python/django並從數據庫訪問數據的機器。這裏的用例是,當多個客戶機正在訪問數據庫並更新時間戳時,如果客戶的系統時間沒有同步(由於缺乏許可,有時候這是不可能的),這將很難找出條目被更新 - 這就是爲什麼最好在服務器上使用系統時間,以便時間戳來自同一時鐘。 – kefeizhou

2

如果你想從一個外國服務器的日期時間(即,而不是一個託管Django應用程序),你將不得不手動掛它的DATATIME使用。您可以使用像select now();之類的SQL命令或SSH之類的命令,例如ssh [email protected] "date +%s"

+0

這比直接執行原始更新sql更復雜(在問題中提到過) – kefeizhou

+0

我的印象是,您希望sql server在Django顯示的表單上顯示時間 - 您是否只需要設置sql server在插入/更新期間是自己的時間? –

5

您可以使用像這樣創建一個自定義值來表示使用的數據庫的當前時間:

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 

然後才能夠使用DatabaseNow在DateTimeField字段:

databaseDependentPatch(models.DateTimeField) 

然後依次終於可以讓你做一個非常乾淨的:

class Operation(models.Model): 
    dateTimeCompleted = models.DateTimeField(null=True) 
    # ... 

operation = # Some previous operation 
operation.dateTimeCompleted = DatabaseNow() 
operation.save() 
+1

事實證明,對於我來說'django_conversions.update'是一個必須使它工作,這是在其他答案中缺少。我正在使用Django 1.6。 –

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() 
+0

我可以知道Django的版本嗎?我在Django 1.6上使用我的項目的示例,但它不工作,因爲Django將使用__str __的返回值而不是as_sql構建SQL。 –

3

我創建了一個Python的Django的插件模塊,可讓您在特定情況下(參見下面的usage)以及在auto_nowauto_now_add列中自動控制DateTimeField對象的使用CURRENT_TIMESTAMP

Django的PG-當前時間戳

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) 
+0

這已經過時了。 – Andrade

4

我扭捏代碼使用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() 
12

接受的答案是過時的。下面是這樣做的電流,最簡單的辦法:

from django.utils import timezone 

timezone.now() 
0

您可以使用數據庫功能Now開始的Django 1.9:

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