2011-09-19 53 views
35

¿Cómo se hace el equivalente de este SQL en Django?Django establecen DateTimeField a la hora del servidor de

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

Particularmente quiero establecer el campo de fecha y hora utilizando la función incorporada de servidor para obtener la hora del sistema desde el servidor que la base de datos se ejecuta en el tiempo y no en la máquina cliente.

Sé que usted puede ejecutar el SQL en bruto directamente, pero estoy buscando una solución más portátil desde las bases de datos tienen diferentes funciones, para sacar la fecha y hora actual.

Editar: algunas personas han mencionado parámetro auto_now. Esto actualiza la fecha y hora en cada modificación, mientras que quiero actualizar la fecha y hora solo en ciertas ocasiones.

Respuesta

1

Tal vez debería echar un vistazo a la documentación:
Modelfields: DateField

La opción 'auto_now' podría ser justo lo que está buscando. También puede usarlo con DateTimeField. Actualiza DateTime cada vez que guardas el modelo. Así que con esa opción establecer para su DateTimeField cabe sufficent para recuperar un registro de datos y guardarlo de nuevo para establecer el momento adecuado.

+0

no quiero actualizar fecha y hora en cada modificación. – kefeizhou

+0

Luego recomiendo Jesse's datetime.now() - solution. – j0ker

47

Como dijo j0ker, si quieres actualización automática de la fecha y hora, utilice la opción auto_now. P.ej. date_modified = models.DateTimeField(auto_now=True).

O si desea hacerlo manualmente, ¿no es una tarea simple con python datetime.now()?

from datetime import datetime 

obj.date_modified = datetime.now() 
+3

Auto_now actualiza el campo de fecha y hora en cada actualización que no quiero. Y datetime.now() de python le proporcionará la fecha y hora actuales en el lado del cliente, lo que no está garantizado ni siquiera cerca de la fecha y hora en el servidor. – kefeizhou

+0

¿Cómo utilizará datetime.now() la fecha y hora del cliente? Todo su código de Python en las vistas se ejecuta en el servidor, por lo que, por supuesto, utiliza la fecha y hora del servidor. – j0ker

+4

Por servidor me refiero a la máquina que aloja la base de datos, y el cliente es la máquina que ejecuta python/django y accede a los datos de la base de datos. El caso de uso aquí es que cuando varias máquinas cliente acceden a la base de datos y actualizan las marcas de tiempo, si la hora del sistema del cliente no está sincronizada (lo que a veces no es posible debido a la falta de permiso) será difícil determinar el orden que las entradas se actualizan; por eso es mejor usar la hora del sistema en el servidor para que las marcas de tiempo sean del mismo reloj. – kefeizhou

2

Si desea que la fecha y hora de un servidor extranjero (es decir, no la que aloja la aplicación Django), vas a tener que clavija de forma manual por un DataTime de usar. Se puede usar un comando SQL como select now(); o algo a través de SSH, como ssh [email protected] "date +%s".

+0

Esto es más complicado que ejecutar una actualización cruda sql directamente (que se mencionó en la pregunta) – kefeizhou

+0

Tenía la impresión de que quería el tiempo del servidor SQL en un formulario visualizado por Django. ¿Simplemente quiere que el servidor sql se configure? es su propio tiempo durante la inserción/actualización? –

5

se puede usar algo como esto para crear un valor personalizado para representar el uso de la hora actual en la base de datos:

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 

Y a continuación, para poder utilizar DatabaseNow en un DateTimeField:

databaseDependentPatch(models.DateTimeField) 

que a su vez, a su vez, finalmente, permite realizar un agradable y limpio:

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

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

Resulta que para mí 'django_conversions.update' es imprescindible para hacerlo funcionar, que falta en algunas otras respuestas. Estoy usando Django 1.6. –

7

Aquí es cómo resolví este problema Espero que ahorra tiempo a alguien:

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) 

Y a continuación, sólo mediante el DBNow() como un valor en el que la actualización y se necesita filtrado:

books = Book.objects.filter(created_on__gt=DBNow()) 

    or: 

book.created_on = DBNow() 
book.save() 
+0

¿Puedo saber la versión de su Django? Estoy usando la muestra con mi proyecto en Django 1.6 pero no funciona, ya que Django construirá el SQL con el valor de retorno de __str__ en lugar del de as_sql. –

3

He creado un módulo plug-in de Python Django que le permite para controlar el uso de CURRENT_TIMESTAMP en los objetos DateTimeField, tanto en casos específicos (consulte usage a continuación) como automáticamente para las columnas auto_now y auto_now_add.

django-PG-corriente-marca de tiempo

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

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

Ejemplo:

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

Esto no está actualizado. – Andrade

4

Mi ajustado código funciona con SQLite, MySQL y postgresql y es un poco más limpio que las soluciones propuestas.

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) 

la activo @ al final de mi archivo models.py así:

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

y utilizar de esta manera:

self.last_pageview = DBCurrentTimestamp() 
12

La respuesta aceptada es obsoleta. Esta es la forma actual y mas simple de hacerlo:

from django.utils import timezone 

timezone.now() 
0

puede utilizar la función de base de datos a partir Now Django 1.9:

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