장고 auto_now 및 auto_now_add


272

장고 1.1.

나는 models.py에 이것을 가지고있다 :

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
기본 자동 증가 int 대신 사용자 정의 기본 키를 사용하고 있습니까? 사용자 지정 기본 키를 사용하면이 문제가 발생한다는 것을 알았습니다. 어쨌든, 당신이 지금까지 그것을 해결했다고 생각합니다. 그러나 버그는 여전히 존재합니다. 그냥 내 0.02 $
tapan

3
하나만 더 상기시켜주세요. update()메소드가 호출 save()되지 않아서 modified필드를 자동으로 업데이트 할 수 없음을 의미합니다
Chemical Programmer

답변:


383

auto_now속성이 설정된 모든 필드 도 상속 editable=False되므로 관리자 패널에 표시되지 않습니다. 과거에 auto_nowauto_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. 에 따라 TZ 인식 또는 순진한 개체를 반환하므로 django.utils.timezone.now()vs.를 사용하십시오 .datetime.datetime.now()datetime.datetimesettings.USE_TZ

OP가 오류를 보인 이유를 해결하기 위해 정확히 알지 못하지만 created에도 불구하고 전혀 채워지지 않은 것처럼 보입니다 auto_now_add=True. 나에게 그것은 버그로 눈에 띄는, 위 내 작은 목록의 항목 # 1을 강조 : auto_nowauto_now_add최상의 색다른 있습니다.


9
그러나 저자 문제의 원인은 무엇입니까? auto_now_add가 때때로 제대로 작동하지 않습니까?
Dmitry Risenberg

5
난 당신과 함께 드미트리입니다. 왜 두 필드가 오류를 발생 시켰는지 궁금합니다. 왜 자신 만의 custom save () 메소드를 작성하는 것이 더 나은지 궁금합니다.
hora

45
save()각 모델 에서 사용자 정의 를 작성하는 것은 auto_now(모든 모델에서 이러한 필드를 사용하기를 원하기 때문에)를 사용하는 것보다 훨씬 고통 스럽습니다 . 왜 그 매개 변수가 작동하지 않습니까?
Paul Tarjan

3
@TM이지만 Django는 스키마를 정의하기 위해 models.py 파일만을 목표로합니다
akaihola

11
나는 격렬하게 동의하지 않는다. 1) editable = False가 정확합니다. 필드를 편집해서는 안되며 데이터베이스가 정확해야합니다. 2) 특히 사용자 정의 SQL 업데이트 또는 사용중인 경우 save ()가 호출되지 않는 모든 종류의 엣지 케이스가 있습니다. 3) 이것은 참조 무결성과 함께 데이터베이스가 실제로 잘하는 것입니다. 데이터베이스를 올바르게 사용하는 것이 올바른 기본값입니다. 여러분이나 제가 생각하는 것보다 더 똑똑한 마음이 이런 식으로 작동하도록 데이터베이스를 설계했기 때문입니다.
Shayne

175

그러나 나는 대답에 표현 된 의견 이 다소 구식 이라고 지적하고 싶었습니다 . 더 최근의 토론 (장고 버그 # 7634# 12785 )에 따르면 auto_now 및 auto_now_add는 아무데도 가고 있지 않으며 원래 토론으로 이동하더라도 커스텀 저장에서 RY에 대한 강력한 논쟁을 찾을 수 있습니다 행동 양식.

더 나은 솔루션이 제공되었지만 (맞춤형 필드 유형), 장고로 만들기에 충분한 운동량을 얻지 못했습니다. 세 줄로 직접 작성할 수 있습니다 ( Jacob Kaplan-Moss의 제안입니다 ).

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

기본값을 호출 가능으로 설정할 수 있다고 가정하면 사용자 정의 필드가 실제로 필요하다고 생각하지 않습니다 (예 : timezone.now). 아래 답변을 참조하십시오.
Josh

6
이것은 auto_add가 Django에서하는 것과 똑같으며, 2010 년 이후로 github.com/django/django/blob/1.8.4/django/db/models/fields/… 입니다. pre_save에 추가 후크가 필요하지 않으면 auto_add를 고수합니다.
jwhitlock

1
Django 1.9에서 저에게 효과가 없었 으므로이 솔루션은 auto_now *와는 달리 어디에서나 작동하지 않습니다. 모든 사용 사례에서 작동하는 유일한 솔루션 ( 'update_fields'arg 문제가
있더라도

4
왜 기본값을 timezone.now로 설정하지만 pre_save 신호가 datetime.datetime.now를 사용하고 있습니까?
Bobort

32

부수적 인 질문에 대해 말하기 : 관리자에서이 필드를 보려면 (편집 할 수는 없지만) readonly_fields관리자 클래스에 추가 할 수 있습니다 .

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

글쎄, 이것은 최신 장고 버전에만 적용됩니다 (1.3 이상)


3
참고 사항 : XxAdmin클래스에 추가해야합니다 . 나는 너무 빨리 읽어 내에 추가하려고 AdminForm또는 ModelForm클래스와 그들이 "읽기 전용 필드를"렌더링되지 않은 이유를 몰랐다. BTW, "읽기 전용 필드 양식을 가질 가능성이 있습니까?
Tomasz Gandor

28

가장 쉬운 (아마도 가장 우아한) 솔루션 default은 호출 가능으로 설정할 수 있다는 사실을 활용하는 것 입니다. 따라서 관리자의 auto_now 특수 처리를 피하려면 다음과 같이 필드를 선언하면됩니다.

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

timezone.now()기본값이 업데이트 되지 않도록 사용하지 않는 것이 중요합니다 (즉, 코드가로드 될 때만 기본값이 설정 됨). 이 작업을 많이하면 사용자 정의 필드를 만들 수 있습니다. 그러나 이것은 이미 생각하기에 꽤 건조합니다.


2
기본값은 auto_now_add (오브젝트가 처음 저장 될 때 설정되는 값)와 다소 비슷하지만 auto_now (오브젝트가 저장 될 때마다 설정되는 값)와 전혀 다릅니다.
Shai Berger

1
@ShaiBerger, 나는 그들이 중요한 방식으로 미묘하다고 생각합니다. 의사는 "자동으로 필드를 설정합니다 ...; 이것은 단순히 무시할 수있는 기본값이 아닙니다."라는 미묘함을 언급했습니다. - docs.djangoproject.com/en/dev/ref/models/fields/...
토마스 - BeeDesk

@ Thomas-BeeDesk : 동의합니다. 따라서 "거의 동등하다".
Shai Berger

1
마이그레이션을 사용하는 경우이 솔루션이 제대로 작동하지 않습니다. 실행할 때마다 makemigrations기본값이 실행 시간으로 해석되므로 기본값 makemigrations이 변경되었다고 생각합니다!
nhinkle

8
@nhinkle, default=timezone.now()권장 사항 이 아닌 지정 하지 default=timezine.now않았습니까? (괄호 없음)?
Josh

18

다음과 같이 모델 클래스를 변경하면 :

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

그러면이 필드가 관리자 변경 페이지에 나타납니다


1
그러나 편집 레코드에서만 작동합니다. 새 레코드를 만들면 날짜 타일 값으로 전달이 무시됩니다. 이 레코드를 변경하면 새로운 값이 설정됩니다.
Anton Danilchenko

2
작동하지만 대신 models.DatetimeField의 models.DateTimeField 수 갈까요은
MATYAS

2
실패 python manage.py makemigrations: KeyError : u'editable '
laoyur

12

내가 읽은 내용과 지금까지 Django에 대한 내 경험에 따르면 auto_now_add는 버그가 있습니다. 나는 jthanism에 동의합니다 --- 깨끗한 정상적인 저장 방법을 무시하고 무엇이 문제인지 알고 있습니다. 이제 건조시키기 위해 TimeStamped라는 추상 모델을 만듭니다.

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()?
코어 덤프 오류

1
좋은 지적입니다. 수입 명세서를 추가했습니다. 사용하는 이유 timezone.now()는 시간대를 인식하고 datetime.datetime.now()시간대는 순진하기 때문입니다. 여기에서 읽을 수 있습니다 : docs.djangoproject.com/en/dev/topics/i18n/timezones
Edward Newell

@EdwardNewell default=timezone.now필드 생성자 대신 저장에서 creation_date를 설정하도록 선택한 이유는 무엇 입니까?
Blackeagle52

흠 .. 어쩌면 난 그냥 생각하지 않았다, 그것은 더 나은 소리.
Edward Newell

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

이것이 우려의 원인입니까?

아니요, 장고는 모델을 저장하는 동안 자동으로 추가하므로 예상됩니다.

추가 질문 : 내 관리 도구에서이 두 필드가 표시되지 않습니다. 예상 되나요?

이 필드는 자동으로 추가되므로 표시되지 않습니다.

위의 내용에 덧붙여서, synack이 말했듯이, django 메일 링리스트에서 이것을 제거하기위한 토론이있었습니다. 왜냐하면 "잘 설계되지 않았고" "핵"이기 때문입니다

내 각 모델에서 사용자 정의 save ()를 작성하는 것은 auto_now를 사용하는 것보다 훨씬 고통입니다.

분명히 모든 모델에 쓸 필요는 없습니다. 한 모델에 쓰고 다른 모델을 상속 할 수 있습니다.

하지만, 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.datetimetimezone.datetimeDateTimeDate


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 버그로 이어질 것입니다.

여기 장고의 기본의 코드 DateTimeField.pre_saveauto_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

새로운 기록은 ATTR가 없습니다 id때문에, getattr(model_instance, 'id')현장에서 어떤 값을 설정하지으로 이어질 것입니다 False를 반환합니다.


7
기본값을 timezone.now ()로 유지하면 마이그레이션을 할 때 실제 날짜와 시간 (이 순간의)이 마이그레이션 파일로 전달됩니다. makemigrations를 호출 할 때마다이 필드의 값이 달라 지므로이를 피해야한다고 생각합니다.
Karan Kumar

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

datetime 및 django.utils.timezone 모듈을 사용할 수 있으므로 timezone.now ()
michel.iamit

모형에 주요 데이터가없는 경우에 대한 질문입니다. 모델을 올바르게 설정 한 경우이 프롬프트가 표시되지 않아도됩니다.
Shayne
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.