web-dev-qa-db-fra.com

django définissez DateTimeField sur l'heure actuelle du serveur

Comment puis-je faire l'équivalent de ce SQL dans django?

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

En particulier, je souhaite définir le champ datetime à l'aide de la fonction intégrée du serveur pour obtenir l'heure système du serveur sur lequel la base de données s'exécutait et non l'heure sur la machine cliente.

Je sais que vous pouvez exécuter le SQL brut directement, mais je recherche une solution plus portable car les bases de données ont différentes fonctions pour obtenir l'heure actuelle.

Edit: peu de gens ont mentionné le paramètre auto_now. Cela met à jour le datetime à chaque modification alors que je ne veux mettre à jour le datetime qu'à certaines occasions.

43
kefeizhou

Comme l'a dit j0ker, si vous voulez une mise à jour automatique de l'horodatage, utilisez l'option auto_now. Par exemple. date_modified = models.DateTimeField(auto_now=True).

Ou si vous voulez le faire manuellement, n'est-ce pas une simple affectation avec python datetime.now()?

from datetime import datetime

obj.date_modified = datetime.now()
54
jsz

La réponse acceptée est obsolète. Voici la manière actuelle et la plus simple de le faire:

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

Voici comment j'ai résolu ce problème. J'espère que cela fait gagner du temps à quelqu'un:

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)

Et puis juste en utilisant le DBNow () comme une valeur où la mise à jour et le filtrage sont nécessaires:

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

    or:

book.created_on = DBNow()
book.save()
8
Chris

Vous pouvez utiliser la fonction de base de données Maintenant démarrage Django 1.9:

from Django.db.models.functions import Now
Model.objects.filter(...).update(timestamp=Now())
7
tvorog

Vous pouvez utiliser quelque chose comme ceci pour créer une valeur personnalisée pour représenter l'utilisation de l'heure actuelle dans la base de données:

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

Et puis pour pouvoir utiliser DatabaseNow sur un DateTimeField:

databaseDependentPatch(models.DateTimeField)

Ce qui à son tour vous permet enfin de faire un Nice and clean:

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

operation = # Some previous operation
operation.dateTimeCompleted = DatabaseNow()
operation.save()
5
David Q Hogan

Mon code modifié fonctionne avec sqlite, mysql et postgresql et est un peu plus propre que les solutions proposées.

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)

Je l'active à la fin de mon fichier models.py comme ceci:

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

et utilisez-le comme ceci:

self.last_pageview = DBCurrentTimestamp()
4
Kukosk

J'ai créé un Python Django qui vous permet de contrôler l'utilisation de CURRENT_TIMESTAMP sur DateTimeField objets, à la fois dans des cas spécifiques (voir usage ci-dessous) ainsi que automatiquement pour auto_now et auto_now_add colonnes.

Django-pg-current-timestamp

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

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

Exemple d'utilisation:

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)
3
Jay Taylor

Si vous voulez que le datetime à partir d'un serveur étranger (c'est-à-dire pas celui qui héberge l'application Django), vous devrez le rattacher manuellement pour un datatime à utiliser. Vous pouvez utiliser un Commande SQL comme select now(); ou quelque chose sur SSH, comme ssh user@Host "date +%s".

2
Mel Boyce

Vous devriez peut-être jeter un œil à la documentation:
Modelfields: DateField

L'option 'auto_now' pourrait être exactement ce que vous recherchez. Vous pouvez également l'utiliser avec DateTimeField. Il met à jour le DateTime chaque fois que vous enregistrez le modèle. Donc, avec cette option définie pour votre DateTimeField, il devrait être suffisant de récupérer un enregistrement de données et de le sauvegarder à nouveau pour régler l'heure correctement.

1
j0ker