Атрибут Mongoengine creation_time у документі

Я намагаюся додати атрибут create_time до моїх документів. Наступним буде приклад:

import datetime

class MyModel(mongoengine.Document):
    creation_date = mongo.DateTimeField()
    modified_date = mongo.DateTimeField(default=datetime.datetime.now)

Моделі Django мають вбудований параметр для своїх DateTimeField об'єктів, таких як add_now та ін. але MongoEngine це не підтримує.

Мені цікаво, чи найкращий спосіб це зробити:

m,created = MyModel.objects.get_or_create()
if created:
    m.creation_date = datetime.datetime.now()

або якщо є кращий, приємніший спосіб.

24

8 Відповіді

Ви можете перевизначити метод збереження.

class MyModel(mongoengine.Document):
    creation_date = mongo.DateTimeField()
    modified_date = mongo.DateTimeField(default=datetime.datetime.now)

    def save(self, *args, **kwargs):
        if not self.creation_date:
            self.creation_date = datetime.datetime.now()
        self.modified_date = datetime.datetime.now()
        return super(MyModel, self).save(*args, **kwargs)
51
додано
Переопределити метод clean замість save має бути краще, документи тут
додано Автор xialu, джерело
@ Brenden1995 Ні, це не працює з оновленням.
додано Автор Willian, джерело
Це саме те, що мені потрібно. Я зрозумів, що біт за замовчуванням, але переоцінити метод збереження для відстеження модифікованого часу ідеально. Дякую :)
додано Автор Dawson, джерело
Проблема з цим, однак, полягає в тому, що функція збереження не буде викликана, якщо ви оновите, а не правильне.
додано Автор Nazariy1995, джерело

На відміну від часу створення створюється атрибут _id - якщо ви робите це:

YourObject.id.generation_time

Дасть вам дату, яку ви маете.

18
додано
Це краще, ніж прийнята відповідь. Я використав @property на таку функцію, щоб отримати створений_time: def created_at (self): повернутися self.id.generation_time, якщо self.id ще немає
додано Автор aaaronic, джерело
Точно, що я шукав, спасибі.
додано Автор Viktor Stískala, джерело

Ви можете використовувати параметр auto_now_add відповідно до документації :

class MyModel(mongoengine.Document):
    creation_date = mongo.DateTimeField(auto_now_add = True)
    modified_date = mongo.DateTimeField(auto_now = True)
7
додано
ці параметри не працюють в mongoengine
додано Автор josephmisiti, джерело
Це найгостріше. Тоді переоцінка збереження, як у прийнятій відповіді, є правильною відповіддю. Я створив патч, щоб додати цю функцію, хоча :)
додано Автор Laur Ivan, джерело
Догляд трохи пояснити?
додано Автор Laur Ivan, джерело
Це не Django чувак ...
додано Автор Ron Reiter, джерело

Одним із гарних рішень є повторне використання одного обробника сигналів для декількох документів.

class User(Document):
    # other fields...
    created_at = DateTimeField(required=True, default=datetime.utcnow)
    updated_at = DateTimeField(required=True)

class Post(Document):
    # other fields...
    created_at = DateTimeField(required=True, default=datetime.utcnow)
    updated_at = DateTimeField(required=True)

def update_timestamp(sender, document, **kwargs):
    document.updated_at = datetime.utcnow()

signals.pre_save.connect(update_timestamp, sender=User)
signals.pre_save.connect(update_timestamp, sender=Post)

Будьте обережні, щоб призначити за замовчуванням невикористану, а не фіксовану величину, наприклад default = datetime.utcnow без () . Деякі інші відповіді на цій сторінці неправильні та можуть призвести до того, що created_at для нових документів завжди буде встановлено до часу першого завантаження вашої програми.

Також завжди краще зберігати дати в UTC ( datetime.utcnow замість datetime.now ) у вашій базі даних.

4
додано
# -*- coding: utf-8 -*-
from mongoengine import *
from mongoengine import signals
from datetime import datetime

class User(Document):
    email = StringField(required=True, unique=True)
    first_name = StringField(max_length=50)
    last_name = StringField(max_length=50)
    # audit fields
    created_on = DateTimeField(default=datetime.now())
    updated_on = DateTimeField(default=datetime.now())

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        document.updated_on = datetime.now()

signals.pre_save.connect(User.pre_save, sender=User)
4
додано

Моїм бажаним рішенням є використання декоратора @property , щоб повернути дату створення, витягнуту з ObjectId:

@property
def creation_stamp(self):
    return self.id.generation_time
3
додано

Якщо ви використовуєте поле відмітки часу в групі документів, ви можете зберегти свій код DRY , замість цього створіть абстрактний документ.

from datetime import datetime
from mongoengine import Document

class CreateUpdateDocument(Document):
    meta = {
        'abstract': True
    }

    # last updated timestamp
    updated_at = DateTimeField(default=datetime.now)

    # timestamp of when entry was created
    created_at = DateTimeField(default=datetime.now)

    def save(self, *args, **kwargs):
        if not self.created_at:
            self.created_at = datetime.now()
        self.updated_at = datetime.now()
        return super(CreateUpdateDocument, self).save(*args, **kwargs)
2
додано
Ви можете поставити self.updated_at = datetime.now() команду else , щоб ви могли зберегти ідею "якщо оновлений_at не має нічого, це означає, що модель ніколи не була оновлена ​​".
додано Автор ldavid, джерело

Традиційно я встановив create_date за умовчанням datetime.now() , а потім приховав поле в формі адміністратора, щоб ви видалили можливість користувача перезаписати правильний вартість Для цього майже немає коду.

Переопределення методу збереження, запропоноване Вілліаном, також ефективне, оскільки ви можете програмно блокувати будь-які оновлення create_date та оновлювати modfied_date одночасно.

0
додано
коли ви кажете "традиційно", ви маєте на увазі використання Django ORM або MongoEngine спеціально?
додано Автор josephmisiti, джерело
ІТ КПІ - Python
ІТ КПІ - Python
625 учасників

Канал обговорень про всякі штуки зі світу пайтону. Прохання: 0. мати повагу одне до одного; 1. не матюкатися в сторону людей; 2. не захламляти тред повідомленнями по одному слову;