Django datetime sorunları (varsayılan = datetime.now ())


283

Aşağıdaki db modelim var:

from datetime import datetime    

class TermPayment(models.Model):
    # I have excluded fields that are irrelevant to the question
    date = models.DateTimeField(default=datetime.now(), blank=True)

Aşağıdakileri kullanarak yeni bir örnek ekliyorum:

tp = TermPayment.objects.create(**kwargs)

Benim sorunum: Veritabanındaki tüm kayıtlar, ilk ödeme tarihi olan tarih alanında aynı değere sahip. Sunucu yeniden başlatıldıktan sonra, bir kayıt yeni tarihe ve diğer kayıtlar birinciyle aynı olur. Bazı veriler önbelleğe alınmış gibi görünüyor, ama nerede bulamıyorum.

veritabanı: mysql 5.1.25

django v1.1.1


1
Böyle bu ?: gibi bir işleve varsayılan mümkün değil mi default=datetime.now- olduğu gibi uğramadan, not now()DateTimeField için değil standart, ama ... kullanışlı Anycase.
viridis

Yanıtlar:


597

datetime.now()her kayıt eklediğinizde değil, model tanımlandığında değerlendiriliyor gibi görünüyor .

Django zaten yapmaya çalıştığınız şeyi başarabilme özelliğine sahiptir:

date = models.DateTimeField(auto_now_add=True, blank=True)

veya

date = models.DateTimeField(default=datetime.now, blank=True)

İkinci örnek ile şu anda sahip olduğunuz şey arasındaki fark parantezin olmamasıdır. Geçerek datetime.nowparantez olmadan, bir rekor eklenen her zaman adı verilecek fiili işlevini geçiyoruz. Eğer iletirseniz datetime.now(), o zaman fonksiyonu değerlendirirsiniz ve dönüş değerini iletirsiniz .

Daha fazla bilgi Django model alan referansında bulunabilir


206
önemli not : auto_now_add kullanmak alanı yönetici tarafından düzenlenemez hale getirir
Jiaaro

7
Harika cevap, teşekkürler. Varsayılan olarak datetime.now ile daha karmaşık bir ifadeyi ifade etmenin bir yolu var mı? örneğin şimdi + 30 gün (aşağıdakiler çalışmaz) expiry = models.DateTimeField(default=datetime.now + timedelta(days=30))
michela

26
@michela datetime.now bir işlevdir ve bir işleve bir zaman çizelgesi eklemeye çalışıyorsunuz. Varsayılan değeri ayarlamak için kendi geri aramanızı tanımlamanız def now_plus_30(): return datetime.now() + timedelta(days = 30)ve kullanmanız gerekirmodels.DateTimeField(default=now_plus_30)
Carson Myers

55
Ya da tabii ki yapabilirsinizdefault=lambda: datetime.now()+timedelta(days=30)
Michael Mior

34
FARKINDA OLMAK auto_now_add kullanarak olduğuna DEĞİL alan her zaman eşit olur çünkü varsayılan kullanarak aynı anda (düzenlenemez) .. ben bu zaten olduğunu söyledi biliyorum ama 'yönetici' sayfasının sadece Metter değil için
VAShhh

115

Kullanmak yerine datetime.nowgerçektenfrom django.utils.timezone import now

Referans:

yani böyle bir şey için gidin:

from django.utils.timezone import now


created_date = models.DateTimeField(default=now, editable=False)

13
Bu çok önemli bir not! datetime.now kullanırsanız, saat dilimi farkında olmayan yerel bir datetime yapabilirsiniz. Daha sonra bunu zaman damgalı bir alanla karşılaştırırsanız auto_now_add(ki bu saat dilimi farkındadır) hatalı saat dilimi farklılıkları nedeniyle yanlış hesaplamalar alabilirsiniz.
Iftah

1
Bu kesinlikle çok önemli ama soruyu kendiliğinden cevaplamıyor.
Çek teknolojisi

1
Kesinlikle daha iyi bir yol
Carmine Tambascia

28

Gönderen belgelere django modeli varsayılan sahada:

Alan için varsayılan değer. Bu bir değer veya çağrılabilir bir nesne olabilir. Callable ise her yeni nesne oluşturulduğunda çağrılır.

Bu nedenle aşağıdakiler işe yaramalıdır:

date = models.DateTimeField(default=datetime.now,blank=True)

1
Bu sadece django 1.8+ 'da mümkündür
David Schumann

@DavidNathan neden bu? Bence her iki seçenek de 1.4'ten önce veya daha önce yapılmıştı default( django-chinese-docs-14.readthedocs.io/en/latest/ref/models/… )
Mark

16

David doğru cevabı verdi. Parantez () , modelin her değerlendirilmesinde çağrılabilir timezone.now () yönteminin çağrılmasını sağlar. Bunu yapmak için () timezone.now () (veya datetime.now () öğesinden kaldırırsanız, naif datetime nesnesi kullanıyorsanız):

default=timezone.now

Daha sonra beklediğiniz gibi çalışır:
Yeni nesneler oluşturulduklarında geçerli tarihi alırlar, ancak manage.py makemigrations / migrate yaptığınızda tarih geçersiz kılınmaz.

Bununla yeni karşılaştım. David'e çok teşekkürler.


10

datetime.now()Sınıf oluşturulduğunda yeni kayıt veritabanına ekleniyor değilken, değerlendirilir.

İstediğinizi başarmak için bu alanı şu şekilde tanımlayın:

date = models.DateTimeField(auto_now_add=True)

Bu şekilde datealan her yeni kayıt için geçerli tarihe ayarlanır.


6

Bunun cevabı aslında yanlış.

Değeri otomatik doldurma (auto_now / auto_now_add varsayılan ile aynı değildir). Varsayılan değer, kullanıcının yepyeni bir nesnesiyse gördüğü değer olacaktır. Ben tipik olarak ne:

date = models.DateTimeField(default=datetime.now, editable=False,)

Bunu bir Yönetici sayfasında temsil etmeye çalışıyorsanız, bunu 'salt okunur' olarak listelediğinizden ve alan adına referansta bulunduğunuzdan emin olun.

read_only = 'date'

Yine, varsayılan değerim genellikle düzenlenebilir olmadığından ve Yönetici sayfaları, aksi belirtilmedikçe düzenlenemez olanları yok sayar. Ancak, varsayılan bir değer ayarlamak ve burada anahtar olan auto_add'yi uygulamak arasında kesinlikle bir fark vardır. Test edin!


6

datetime.now()sınıfınız somutlaştırıldığında bir kez değerlendiriliyor. İşlev datetime.nowdöndürülecek ve ardından değerlendirilecek parantezleri kaldırmayı deneyin . Benim için varsayılan değerleri ayarlama ile aynı sorunu vardı ve DateTimeFieldbenim çözüm burada yazdı .


5

Python dil referansından, İşlev tanımları altında :

Varsayılan parametre değerleri, işlev tanımı yürütüldüğünde değerlendirilir. Bu, ifadenin işlev tanımlandığında bir kez değerlendirildiği ve her çağrı için aynı “önceden hesaplanmış” değerin kullanıldığı anlamına gelir.

Neyse ki, aşağıdaki auto_nowargümanı kullanırsanız, Django'nun istediğinizi yapmanın bir yolu vardır DateTimeField:

date = models.DateTimeField(auto_now=True)

DateTimeField için Django belgelerine bakın .


0

Django 3.0 auto_now_addile çalışmak gibi görünüyorauto_now

reg_date=models.DateField(auto_now=True,blank=True)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.