Django auto_now और auto_now_add


272

Django 1.1 के लिए।

मेरे पास अपने मॉडल में है:

class User(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

एक पंक्ति को अद्यतन करते समय मुझे मिलता है:

[Sun Nov 15 02:18:12 2009] [error] /home/ptarjan/projects/twitter-meme/django/db/backends/mysql/base.py:84: Warning: Column 'created' cannot be null
[Sun Nov 15 02:18:12 2009] [error]   return self.cursor.execute(query, args)

मेरे डेटाबेस का प्रासंगिक हिस्सा है:

  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,

क्या यह चिंता का कारण है?

साइड सवाल: मेरे व्यवस्थापक टूल में, वे दो फ़ील्ड दिखाई नहीं दे रहे हैं। क्या यह अपेक्षित है?


3
क्या आप डिफ़ॉल्ट ऑटो-इंक्रीमेंट इंट के बजाय कस्टम प्राथमिक कुंजी का उपयोग कर रहे थे? मुझे पता चला कि कस्टम प्राथमिक कुंजी का उपयोग करने से यह समस्या होती है। वैसे भी, मुझे लगता है कि आप इसे अब तक हल कर चुके हैं। लेकिन बग अभी भी मौजूद है। बस मेरे 0.02 $
तपन

3
याद दिलाने के लिए बस एक और बात। update()पद्धति कॉल नहीं करेगी save()जिसका अर्थ है कि यह modifiedफ़ील्ड को स्वचालित रूप से अपडेट नहीं कर सकता है
रासायनिक प्रोग्रामर

जवाबों:


383

auto_nowविशेषता सेट वाला कोई भी फ़ील्ड इनहेरिट भी करेगा editable=Falseऔर इसलिए व्यवस्थापक पैनल में दिखाई नहीं देगा। अतीत में तर्क auto_nowऔर auto_now_addतर्क को दूर करने के बारे में बात की गई है, और हालांकि वे अभी भी मौजूद हैं, मुझे लगता है कि आप कस्टम save()पद्धति का उपयोग करके बेहतर हैं ।

इसलिए, इस काम को ठीक से करने के लिए, मैं अनुशंसा करता हूं कि आप इसका उपयोग न करें auto_nowया auto_now_addइसके बजाय अपने save()तरीके को परिभाषित करें, जो कि createdकेवल तभी अपडेट किया idजाता है जब सेट नहीं किया जाता है (जैसे कि आइटम पहली बार बनाया गया है), और क्या यह modifiedहर बार अपडेट होता है आइटम बच जाता है।

मैंने अन्य प्रोजेक्ट्स के साथ ठीक वही काम किया है जो मैंने Django का उपयोग करके लिखा है, और इसलिए आपका save()ऐसा दिखेगा:

from django.utils import timezone

class User(models.Model):
    created     = models.DateTimeField(editable=False)
    modified    = models.DateTimeField()

    def save(self, *args, **kwargs):
        ''' On save, update timestamps '''
        if not self.id:
            self.created = timezone.now()
        self.modified = timezone.now()
        return super(User, self).save(*args, **kwargs)

उम्मीद है की यह मदद करेगा!

टिप्पणियों के जवाब में संपादित करें:

कारण है कि मैं सिर्फ save()इन क्षेत्रों के तर्कों पर भरोसा करते हुए ओवरलोडिंग के साथ चिपक जाता हूं , दो गुना है:

  1. उपर्युक्त उतार-चढ़ाव उनकी विश्वसनीयता के साथ। ये तर्क प्रत्येक प्रकार के डेटाबेस पर बहुत अधिक निर्भर हैं जो कि Django जानता है कि किसी दिनांक / समय स्टैम्प फ़ील्ड के साथ कैसे व्यवहार किया जाए, और हर रिलीज़ के बीच टूटने और / या बदलने के लिए लगता है। (जो मुझे लगता है कि उन्हें पूरी तरह से हटाने के लिए कॉल के पीछे प्रेरणा है)।
  2. तथ्य यह है कि वे केवल DateField, DateTimeField और TimeField पर काम करते हैं, और इस तकनीक का उपयोग करके आप किसी भी आइटम को सहेजे जाने पर किसी भी फ़ील्ड प्रकार को स्वचालित रूप से पॉप्युलेट करने में सक्षम होते हैं।
  3. django.utils.timezone.now()बनाम का उपयोग करें datetime.datetime.now(), क्योंकि यह एक TZ- जागरूक या अनुभवहीन datetime.datetimeवस्तु पर निर्भर करेगा settings.USE_TZ

यह पता करने के लिए कि ओपी ने त्रुटि क्यों देखी, मुझे ठीक से पता नहीं है, लेकिन ऐसा लगता createdहै कि होने के बावजूद भी बिल्कुल भी आबादी नहीं है auto_now_add=True। मेरे लिए यह एक बग के रूप में बाहर खड़ा है, और ऊपर मेरी छोटी सूची में # 1 आइटम को रेखांकित करता है: auto_nowऔर auto_now_addसबसे अच्छे रूप में परतदार हैं।


9
लेकिन लेखक की समस्या का स्रोत क्या है? क्या Auto_now_add कभी-कभी अनुचित तरीके से काम करता है?
दिमित्री रिसेनबर्ग

5
मैं तुम्हारे साथ दिमित्री हूँ। मैं इस बात से उत्सुक हूं कि दो क्षेत्रों ने त्रुटियों को क्यों फेंका .. और मैं इससे भी अधिक उत्सुक हूं कि आप ऐसा क्यों सोचते हैं कि अपना स्वयं का कस्टम सेव () तरीका बेहतर है?
होरा

45
save()मेरे प्रत्येक मॉडल पर रिवाज़ लिखने से अधिक दर्द होता है auto_now(जैसे मुझे अपने सभी मॉडलों पर इन क्षेत्रों को पसंद है)। क्यों नहीं उन लोगों को काम?
पॉल टारजन

3
@ TM, लेकिन इसके लिए आपको सीधे अपने db के साथ फ़िडलिंग की आवश्यकता होती है, जबकि Django का उद्देश्य स्कीमा को परिभाषित करने के लिए केवल
मॉडिफ़ाइड

11
मैं असहमत हूं, सख्ती से। 1) संपादन योग्य = गलत सही है, आपको फ़ील्ड को संपादित नहीं करना चाहिए, आपके डेटाबेस को सटीक होना चाहिए। 2) सभी प्रकार के किनारे के मामले हैं जहां बचत () को कॉल नहीं किया जा सकता है, खासकर जब कस्टम SQL अपडेट या जो भी उपयोग किया जा रहा है। 3) यह कुछ डेटाबेस वास्तव में संदर्भात्मक अखंडता के साथ और इतने पर अच्छा है। डेटाबेस को सही होने के लिए भरोसा करना एक अच्छा डिफ़ॉल्ट है, क्योंकि आपके या मेरे से अधिक चालाक दिमागों ने इस तरह से काम करने के लिए डेटाबेस तैयार किया है।
शायने

175

लेकिन मैं यह बताना चाहता था कि स्वीकृत उत्तर में व्यक्त की गई राय कुछ पुरानी है। हाल की चर्चाओं (django बग्स # 7634 और # 12785 ) के अनुसार, auto_now और auto_now_add कहीं नहीं जा रहे हैं, और यहां तक ​​कि अगर आप मूल चर्चा में जाते हैं , तो आपको RY के खिलाफ मजबूत तर्क मिलेंगे (जैसा कि कस्टम सेव में DRY में) तरीकों।

एक बेहतर समाधान की पेशकश की गई है (कस्टम फ़ील्ड प्रकार), लेकिन इसे django में बनाने के लिए पर्याप्त गति प्राप्त नहीं हुई। आप अपनी खुद की तीन पंक्तियों में लिख सकते हैं (यह जैकब कपलान-मॉस का सुझाव है )।

from django.db import models
from django.utils import timezone


class AutoDateTimeField(models.DateTimeField):
    def pre_save(self, model_instance, add):
        return timezone.now()

#usage
created_at = models.DateField(default=timezone.now)
updated_at = models.AutoDateTimeField(default=timezone.now)

1
तीन लाइन कस्टम फ़ील्ड यहाँ है: लिंक
hgcrpd

मुझे नहीं लगता कि कोई कस्टम फ़ील्ड वास्तव में आवश्यक है जिसे आप एक कॉल करने योग्य (यानी, टाइमज़ोन.वन) पर डिफ़ॉल्ट सेट कर सकते हैं। नीचे मेरा जवाब देखें।
जोश

6
यह वही चीज़ है जो Auto_add Django में करती है, और 2010 से है: github.com/django/django/blob/1.8.4/django/db/models/fields/… । जब तक मुझे pre_save में अतिरिक्त हुक की आवश्यकता नहीं होती, मैं auto_add के साथ चिपका रहा हूं।
16

1
Django 1.9 के साथ मेरे लिए काम नहीं किया, इसलिए यह समाधान हर जगह काम नहीं कर रहा है, क्योंकि यह कभी भी auto_now * के लिए नहीं था। एकमात्र समाधान जो हर उपयोग के मामले में काम करता है (यहां तक ​​कि 'update_fields' arg समस्या के साथ) ओवरराइडिंग बचा रहा है
danius

4
आप डिफ़ॉल्ट को timezone.now पर सेट क्यों करते हैं, लेकिन pre_save सिग्नल datetime.datetime.now का उपयोग कर रहा है?
बोबोर्ट

32

एक साइड प्रश्न के बारे में बात करना: यदि आप इस फ़ील्ड को व्यवस्थापक में देखना चाहते हैं (हालांकि, आप इसे संपादित नहीं कर पाएंगे), तो आप readonly_fieldsअपने व्यवस्थापक वर्ग में जोड़ सकते हैं ।

class SomeAdmin(ModelAdmin):
    readonly_fields = ("created","modified",)

खैर, यह केवल नवीनतम Django संस्करणों पर लागू होता है (मेरा मानना ​​है, 1.3 और ऊपर)


3
नोट करने के लिए महत्वपूर्ण: यह XxAdminवर्ग में जोड़ा जाना चाहिए । मैंने इसे बहुत जल्दी पढ़ा और इसे अपने AdminFormया ModelFormकक्षाओं में जोड़ने की कोशिश की और पता नहीं क्यों वे "केवल पढ़ने के लिए फ़ील्ड" नहीं दे रहे थे। BTW, क्या एक फॉर्म में केवल "रीड-ओनली फील्ड्स" के सही होने की संभावना है?
टॉमस गैंडर

28

मुझे लगता है कि सबसे आसान (और शायद सबसे सुरुचिपूर्ण) समाधान यहां इस तथ्य का लाभ उठाने के लिए है कि आप defaultएक कॉल करने योग्य सेट कर सकते हैं । इसलिए, auto_now के व्यवस्थापन विशेष से निपटने के लिए, आप केवल फ़ील्ड को घोषित कर सकते हैं:

from django.utils import timezone
date_filed = models.DateField(default=timezone.now)

यह महत्वपूर्ण है कि आप उपयोग न करें timezone.now()क्योंकि डिफ़ॉल्ट मान अपडेट नहीं होगा (यानी, डिफ़ॉल्ट केवल तभी सेट हो जाता है जब कोड लोड होता है)। यदि आप अपने आप को ऐसा करते हुए पाते हैं, तो आप एक कस्टम फ़ील्ड बना सकते हैं। हालाँकि, यह काफी DRY है जो मुझे पहले से लगता है।


2
डिफ़ॉल्ट रूप से auto_now_add के लिए अधिक-या-कम समतुल्य है (जब ऑब्जेक्ट पहली बार सहेजा जाता है तो मान सेट करें), लेकिन यह auto_now (हर बार ऑब्जेक्ट सहेजे जाने पर हर बार सेट मूल्य) की तरह नहीं होता है।
बर्जर

1
@ भाई, मुझे लगता है कि वे एक महत्वपूर्ण तरीके से अलग-अलग हैं। डॉक्टर ने सूक्ष्मता से कहा: "स्वचालित रूप से फ़ील्ड सेट करें ..., यह केवल एक डिफ़ॉल्ट मान नहीं है जिसे आप ओवरराइड कर सकते हैं।" - docs.djangoproject.com/en/dev/ref/models/fields/…
थॉमस - BeeDesk

@ थॉमस-बीडस्क: सहमत। इसलिए, "अधिक-या-कम समकक्ष"।
Shai Berger

1
यदि आप माइग्रेशन का उपयोग कर रहे हैं तो यह समाधान खराब तरीके से काम करता है। हर बार जब आप makemigrationsइसे चलाते हैं तो डिफ़ॉल्ट रूप से आपके द्वारा चलाए जाने वाले समय की व्याख्या करता है makemigrations, और इसलिए सोचता है कि डिफ़ॉल्ट मान बदल गया है!
15'15

8
@ जानिए, क्या आप निश्चित हैं कि default=timezone.now()सिफारिश करने के बजाय निर्दिष्ट नहीं कर रहे हैं : default=timezine.now(कोई कोष्ठक नहीं)?
जोश

18

यदि आप अपने मॉडल वर्ग को इस तरह बदलते हैं:

class MyModel(models.Model):
    time = models.DateTimeField(auto_now_add=True)
    time.editable = True

फिर यह फ़ील्ड मेरे व्यवस्थापक परिवर्तन पृष्ठ में दिखाई देगी


1
लेकिन यह केवल एडिट रिकॉर्ड पर काम करता है। जब मैं नया रिकॉर्ड बनाता हूं - तो टाइल मूल्य को नजरअंदाज कर दिया गया। जब मैं यह रिकॉर्ड बदलता हूं - नया मान सेट होता है।
एंटोन डैनिलचेंको

2
काम करता है, लेकिन यह मॉडल होना चाहिए। मॉडल के बजाय DateTimeField.DatetimeField
matyas

2
इसमें विफल python manage.py makemigrations: KeyError: u'editable '
laoyur

12

मैंने जो कुछ पढ़ा है और जोंगो के साथ अब तक का मेरा अनुभव है, उसके आधार पर auto_now_add छोटी गाड़ी है। मैं jthanism से सहमत हूँ --- यह साफ है कि सामान्य बचत विधि को ओवरराइड करें और आप जानते हैं कि क्या है। अब, इसे सूखने के लिए, टाइमस्टैम्पड नामक एक सार मॉडल बनाएं:

from django.utils import timezone

class TimeStamped(models.Model):
    creation_date = models.DateTimeField(editable=False)
    last_modified = models.DateTimeField(editable=False)

    def save(self, *args, **kwargs):
        if not self.creation_date:
            self.creation_date = timezone.now()

        self.last_modified = timezone.now()
        return super(TimeStamped, self).save(*args, **kwargs)

    class Meta:
        abstract = True

और फिर, जब आप एक मॉडल चाहते हैं जिसमें इस समय-स्टांप व्यवहार होता है, तो बस उपवर्ग:

MyNewTimeStampyModel(TimeStamped):
    field1 = ...

यदि आप चाहते हैं कि फ़ील्ड्स व्यवस्थापन में दिखें, तो बस editable=Falseविकल्प को हटा दें


1
कौन सा timezone.now()तुम यहाँ का उपयोग कर रहे हैं? मैं मान रहा हूं django.utils.timezone.now(), लेकिन मैं सकारात्मक नहीं हूं। इसके अलावा, timezone.now()बजाय उपयोग क्यों datetime.datetime.now()?
coredumperror

1
अच्छे अंक। मैंने आयात विवरण जोड़ा। उपयोग करने timezone.now()का कारण यह है कि यह टाइमजोन जागरूक है, जबकि datetime.datetime.now()टाइमजोन भोला है। आप इसके बारे में यहां पढ़ सकते हैं: docs.djangoproject.com/en/dev/topics/i18n/timezones
एडवर्ड नेवेल

@EdwardNewell आपने default=timezone.nowफ़ील्ड निर्माणकर्ता के बजाय, निर्माण में बचत करने के लिए चयन क्यों किया ?
Blackeagle52

हम्म .. शायद मैं सिर्फ इसके बारे में नहीं सोचा था, यह बेहतर ध्वनि करता है।
एडवर्ड नेवेल

2
खैर एक ऐसा मामला है जहां last_modified अपडेट नहीं किया जाएगा: जब update_fieldsarg प्रदान किया जाता है और 'last_modified' सूची में नहीं है, तो मैं जोड़ूंगा:if 'update_fields' in kwargs and 'last_modifed' not in kwargs['update_fields']: kwargs['update_fields'].append('last_modified')
danius

5

क्या यह चिंता का कारण है?

नहीं, मॉडल को सहेजते समय Django स्वचालित रूप से इसे आपके लिए जोड़ता है, इसलिए, यह अपेक्षित है।

साइड प्रश्न: मेरे व्यवस्थापक टूल में, वे 2 फ़ील्ड दिखाई नहीं दे रहे हैं। क्या यह अपेक्षित है?

चूंकि ये फ़ील्ड ऑटो जोड़े गए हैं, इसलिए इन्हें नहीं दिखाया गया है।

ऊपर जोड़ने के लिए, जैसा कि सिंकैक ने कहा, इसे हटाने के लिए django मेलिंग सूची पर एक बहस हुई है, क्योंकि, यह "अच्छी तरह से डिज़ाइन नहीं किया गया" और "एक हैक" है।

मेरे प्रत्येक मॉडल पर कस्टम सेव () लिखना ऑटो_नॉट का उपयोग करने की तुलना में बहुत अधिक दर्द है

जाहिर है आपको इसे हर मॉडल पर लिखना नहीं है। आप इसे एक मॉडल में लिख सकते हैं और दूसरों से इसे विरासत में ले सकते हैं।

लेकिन, जैसा कि auto_addऔर जैसा है auto_now_add, मैं खुद एक विधि लिखने की कोशिश करने के बजाय उनका उपयोग करूंगा।


3

मुझे काम पर आज कुछ इसी तरह की जरूरत थी। डिफ़ॉल्ट मान होना चाहिए timezone.now(), लेकिन इनहेरिट करने वाले एडमिन और क्लास व्यूज दोनों में संपादन योग्य है FormMixin, इसलिए मेरे models.pyकोड में बनाए गए निम्न कोडों ने उन आवश्यकताओं को पूरा किया:

from __future__ import unicode_literals
import datetime

from django.db import models
from django.utils.functional import lazy
from django.utils.timezone import localtime, now

def get_timezone_aware_now_date():
    return localtime(now()).date()

class TestDate(models.Model):
    created = models.DateField(default=lazy(
        get_timezone_aware_now_date, datetime.date)()
    )

के लिए DateTimeField, मैं को दूर लगता है कि .date()समारोह और परिवर्तन से datetime.dateकरने के लिए datetime.datetimeया बेहतर timezone.datetime। मैंने इसके साथ DateTimeकेवल कोशिश नहीं की है Date


2

आप timezone.now()निर्मित और auto_nowसंशोधित के लिए उपयोग कर सकते हैं :

from django.utils import timezone
class User(models.Model):
    created = models.DateTimeField(default=timezone.now())
    modified = models.DateTimeField(auto_now=True)

यदि आप डिफ़ॉल्ट के बजाय कस्टम प्राथमिक कुंजी का उपयोग कर रहे हैं auto- increment int, auto_now_addतो बग का कारण होगा।

यहाँ Django के डिफ़ॉल्ट के कोड है DateTimeField.pre_save साथ auto_nowऔर auto_now_add:

def pre_save(self, model_instance, add):
    if self.auto_now or (self.auto_now_add and add):
        value = timezone.now()
        setattr(model_instance, self.attname, value)
        return value
    else:
        return super(DateTimeField, self).pre_save(model_instance, add)

मुझे यकीन नहीं है कि पैरामीटर क्या addहै। मुझे उम्मीद है कि यह कुछ इस तरह होगा:

add = True if getattr(model_instance, 'id') else False

नए रिकॉर्ड में एटीआर नहीं होगा id, इसलिए getattr(model_instance, 'id')फाल्स वापस आ जाएगा और क्षेत्र में कोई मूल्य निर्धारित नहीं करेगा।


7
मैंने देखा है कि अगर हम डिफ़ॉल्ट को timezone.now () के रूप में रखते हैं, तो जब आप नोटिफ़िकेशन करते हैं, तो वास्तविक दिनांक और समय (इस क्षण का) माइग्रेशन फ़ाइल में पास हो जाता है। मुझे लगता है कि हमें इससे बचना चाहिए क्योंकि हर बार जब आप कॉल करते हैं तो इस क्षेत्र का एक अलग मूल्य होगा।
करण कुमार

2

अपने व्यवस्थापक प्रदर्शन के लिए, इस उत्तर को देखें ।

नोट: auto_nowऔर डिफ़ॉल्ट रूप auto_now_addसे सेट किया editable=Falseगया है, यही वजह है कि यह लागू होता है।


1

auto_now=TrueDjango 1.4.1 में मेरे लिए काम नहीं किया, लेकिन नीचे के कोड ने मुझे बचा लिया। यह टाइमजोन जागरूक डेटाइम के लिए है।

from django.utils.timezone import get_current_timezone
from datetime import datetime

class EntryVote(models.Model):
    voted_on = models.DateTimeField(auto_now=True)

    def save(self, *args, **kwargs):
        self.voted_on = datetime.now().replace(tzinfo=get_current_timezone())
        super(EntryVote, self).save(*args, **kwargs)

1
class Feedback(models.Model):
   feedback = models.CharField(max_length=100)
   created = models.DateTimeField(auto_now_add=True)
   updated = models.DateTimeField(auto_now=True)

यहां, हमने ऐसे कॉलम बनाए और अपडेट किए हैं, जिन्हें बनाते समय टाइमस्टैम्प होगा और जब कोई संशोधित प्रतिक्रिया देगा।

auto_now_add एक उदाहरण बनते समय समय सेट करेगा जबकि auto_now समय सेट करेगा जब कोई व्यक्ति अपनी प्रतिक्रिया संशोधित करेगा।


-1

यदि आप दक्षिण का उपयोग कर रहे हैं और डेटाबेस में फ़ील्ड जोड़ने की तिथि को डिफ़ॉल्ट करना चाहते हैं, तो इसका उत्तर यहां दिया गया है:

विकल्प 2 तब चुनें : datetime.datetime.now ()

इस तरह दिखता है:

$ ./manage.py schemamigration myapp --auto
 ? The field 'User.created_date' does not have a default specified, yet is NOT NULL.
 ? Since you are adding this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ? Please select a choice: 2
 ? Please enter Python code for your one-off default value.
 ? The datetime module is available, so you can do e.g. datetime.date.today()
 >>> datetime.datetime.now()
 + Added field created_date on myapp.User

यह अद्यतन किया जाएगा: डेटाटाइम और django.utils.timezone मॉड्यूल उपलब्ध हैं, इसलिए आप जैसे कर सकते हैं timezone.now ()
michel.iamit

यह तब के लिए एक प्रश्नावली है जब आपका मॉडल महत्वपूर्ण डेटा गायब है। यदि आप अपने मॉडल को सही तरीके से सेट करते हैं, तो आपको कभी भी इस संकेत को देखने की आवश्यकता नहीं होनी चाहिए।
शाइनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.