일시적으로 auto_now / auto_now_add 사용 안 함
다음과 같은 모델이 있습니다.
class FooBar(models.Model):
createtime = models.DateTimeField(auto_now_add=True)
lastupdatetime = models.DateTimeField(auto_now=True)
일부 모델 인스턴스(데이터 마이그레이션 시 사용)에 대해 두 개의 날짜 필드를 덮어쓰려고 합니다.현재 솔루션은 다음과 같습니다.
for field in new_entry._meta.local_fields:
if field.name == "lastupdatetime":
field.auto_now = False
elif field.name == "createtime":
field.auto_now_add = False
new_entry.createtime = date
new_entry.lastupdatetime = date
new_entry.save()
for field in new_entry._meta.local_fields:
if field.name == "lastupdatetime":
field.auto_now = True
elif field.name == "createtime":
field.auto_now_add = True
더 좋은 해결책이 있습니까?
저는 최근에 애플리케이션을 테스트하는 동안 이 상황에 직면했습니다.만료된 타임스탬프를 "강제"해야 했습니다.저의 경우, 저는 쿼리 세트 업데이트를 사용하여 속임수를 썼습니다.다음과 같이:
# my model
class FooBar(models.Model):
title = models.CharField(max_length=255)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=True)
# my tests
foo = FooBar.objects.get(pk=1)
# force a timestamp
lastweek = datetime.datetime.now() - datetime.timedelta(days=7)
FooBar.objects.filter(pk=foo.pk).update(updated_at=lastweek)
# do the testing.
auto_now/auto_now_add를 기존과 다른 방식으로 비활성화할 수는 없습니다.이러한 값을 변경할 수 있는 유연성이 필요하다면,auto_now
/auto_now_add
최선의 선택이 아닙니다.사용하기가 더 유연한 경우가 많습니다.default
"/어플리케이션"을 덮어씁니다.save()
개체가 저장되기 직전에 조작을 수행하는 메서드입니다.
용사를 합니다.default
재정의된 및라이드된save()
문제를 해결하는 한 가지 방법은 모델을 다음과 같이 정의하는 것입니다.
class FooBar(models.Model):
createtime = models.DateTimeField(default=datetime.datetime.now)
lastupdatetime = models.DateTimeField()
def save(self, *args, **kwargs):
if not kwargs.pop('skip_lastupdatetime', False):
self.lastupdatetime = datetime.datetime.now()
super(FooBar, self).save(*args, **kwargs)
자동 마지막 업데이트 시간 변경을 건너뛸 코드에서 다음을 사용합니다.
new_entry.save(skip_lastupdatetime=True)
가 관리 위치에 save()는되며 skip_lastupdatetime 인수와 합니다.auto_now
.
은 또한 있다니습수도를 할 수 .update_fields
의 매 변 수 개의 파라미터.save()
그리고 당신의 것을 전달합니다.auto_now
◦ 다음은 예입니다.
# Date you want to force
new_created_date = date(year=2019, month=1, day=1)
# The `created` field is `auto_now` in your model
instance.created = new_created_date
instance.save(update_fields=['created'])
Django의 문서에 대한 설명은 다음과 같습니다. https://docs.djangoproject.com/en/stable/ref/models/instances/ #저장할 필드 지정
저는 질문자가 제안한 것을 사용하여 몇 가지 기능을 만들었습니다.다음은 사용 사례입니다.
turn_off_auto_now(FooBar, "lastupdatetime")
turn_off_auto_now_add(FooBar, "createtime")
new_entry.createtime = date
new_entry.lastupdatetime = date
new_entry.save()
구현은 다음과 같습니다.
def turn_off_auto_now(ModelClass, field_name):
def auto_now_off(field):
field.auto_now = False
do_to_model(ModelClass, field_name, auto_now_off)
def turn_off_auto_now_add(ModelClass, field_name):
def auto_now_add_off(field):
field.auto_now_add = False
do_to_model(ModelClass, field_name, auto_now_add_off)
def do_to_model(ModelClass, field_name, func):
field = ModelClass._meta.get_field_by_name(field_name)[0]
func(field)
유사한 기능을 만들어 다시 켤 수 있습니다.
저는 재사용 가능성을 위해 컨텍스트 관리자의 길을 갔습니다.
@contextlib.contextmanager
def suppress_autotime(model, fields):
_original_values = {}
for field in model._meta.local_fields:
if field.name in fields:
_original_values[field.name] = {
'auto_now': field.auto_now,
'auto_now_add': field.auto_now_add,
}
field.auto_now = False
field.auto_now_add = False
try:
yield
finally:
for field in model._meta.local_fields:
if field.name in fields:
field.auto_now = _original_values[field.name]['auto_now']
field.auto_now_add = _original_values[field.name]['auto_now_add']
다음과 같이 사용:
with suppress_autotime(my_object, ['updated']):
my_object.some_field = some_value
my_object.save()
짜잔.
테스트를 작성할 때 이것을 보는 사람들을 위해, 시간을 속일 수 있는 freezegun이라는 파이썬 라이브러리가 있습니다 - 그래서 언제.auto_now_add
코드가 실행되면 실제로 원하는 시간을 얻을 수 있습니다.그래서:
from datetime import datetime, timedelta
from freezegun import freeze_time
with freeze_time('2016-10-10'):
new_entry = FooBar.objects.create(...)
with freeze_time('2016-10-17'):
# use new_entry as you wish, as though it was created 7 days ago
장식기로도 사용할 수 있습니다. 기본 문서는 위의 링크를 참조하십시오.
오버라이드할 수 있습니다.auto_now_add
특별 규정 없이
특정 날짜의 개체를 만들 때 다음과 같은 문제가 발생했습니다.
Post.objects.create(publication_date=date, ...)
publication_date = models.DateField(auto_now_add=True)
.
그래서 제가 한 일은 이렇습니다.
post = Post.objects.create(...)
post.publication_date = date
post.save()
으로 성적으습다니었재되를 무시했습니다.auto_now_add
.
해결책으로 하는 것은 보다장인해로으책지정, 위순선우결입니다.save
방법이 방법입니다. https://code.djangoproject.com/ticket/16583
장고 문서에서
날짜 필드.자동_지금_추가
개체를 처음 만들 때 필드를 지금으로 자동 설정합니다.타임스탬프를 만드는 데 유용합니다.현재 날짜는 항상 사용됩니다. 이 날짜는 재정의할 수 있는 기본값이 아닙니다.따라서 개체를 만들 때 이 필드에 값을 설정하더라도 무시됩니다.이 필드를 수정하려면 대신 다음을 설정합니다.
날짜 필드의 경우:default=date.today
today에서 datetime.date.today로 이동합니다.
::default=timezone.now
django.s.timezone.now에서.
마이그레이션 중에 DateTime 필드에 대해 auto_now를 사용하지 않도록 설정해야 했고 이 작업을 수행할 수 있었습니다.
events = Events.objects.all()
for event in events:
for field in event._meta.fields:
if field.name == 'created_date':
field.auto_now = False
event.save()
파티에 늦었지만 다른 몇 가지 답변과 마찬가지로 데이터베이스 마이그레이션 중에 사용한 솔루션입니다.다른 답변과 다른 점은 모델에 대한 모든 auto_now 필드가 비활성화된다는 것입니다. 이러한 필드는 둘 이상의 필드가 필요하지 않습니다.
def disable_auto_now_fields(*models):
"""Turns off the auto_now and auto_now_add attributes on a Model's fields,
so that an instance of the Model can be saved with a custom value.
"""
for model in models:
for field in model._meta.local_fields:
if hasattr(field, 'auto_now'):
field.auto_now = False
if hasattr(field, 'auto_now_add'):
field.auto_now_add = False
그런 다음 이 기능을 사용하기 위해 다음과 같은 작업을 수행할 수 있습니다.
disable_auto_now_fields(Document, Event, ...)
그리고 그것은 당신의 모든 것을 뚫고 핵이 될 것입니다.auto_now
그리고.auto_now_add
전달하는 모든 모델 클래스에 대한 필드입니다.
https://stackoverflow.com/a/35943149/1731460 의 컨텍스트 관리자의 약간 더 깨끗한 버전입니다.
참고: 보기/양식 또는 Django 앱의 어느 곳에서도 이 컨텍스트 관리자를 사용하지 마십시오.이 컨텍스트 관리자는 내부 필드 상태를 변경합니다(일시적으로 auto_now 및 auto_now_add를 False로 설정).이로 인해 Django는 동시 요청(즉, 동일한 프로세스, 다른 스레드)을 위해 컨텍스트 관리자의 본문을 실행하는 동안 이러한 필드를 timezone.now()로 채우지 않습니다.
Django 앱과 동일한 프로세스에서 실행되지 않는 독립 실행형 스크립트(예: 관리 명령, 데이터 마이그레이션)에 사용할 수 있습니다.
from contextlib import contextmanager
@contextmanager
def suppress_auto_now(model, field_names=None):
"""
Temp disable auto_now and auto_now_add for django fields
@model - model class or instance
@field_names - list of field names to suppress or all model's
fields that support auto_now_add, auto_now"""
def get_auto_now_fields(user_selected_fields):
for field in model._meta.get_fields():
field_name = field.name
if user_selected_fields and field_name not in user_selected_fields:
continue
if hasattr(field, 'auto_now') or hasattr(field, 'auto_now_add'):
yield field
fields_state = {}
for field in get_auto_now_fields(user_selected_fields=field_names):
fields_state[field] = {
'auto_now': field.auto_now,
'auto_now_add': field.auto_now_add
}
for field in fields_state:
field.auto_now = False
field.auto_now_add = False
try:
yield
finally:
for field, state in fields_state.items():
field.auto_now = state['auto_now']
field.auto_now_add = state['auto_now_add']
팩토리(팩토리보이)에서도 사용할 수 있습니다.
with suppress_auto_now(Click, ['created']):
ClickFactory.bulk_create(post=obj.post, link=obj.link, created__iter=created)
장고의 복사본 - 모델.DateTimeField - 동적으로 auto_now_add 값 변경
첫vmdk에서 어디에 있는지입니다.저는.py 의 휴식 . 를 들어, serializer.py 의 frame 에 . 예를 들어.__init__
아직 수 . 수 . 에 serializer와 Model 사이에 . 이제 _internal_value로 모델 클래스를 얻을 수 있습니다. Field를 얻은 후 다음 예제와 같이 필드 속성을 수정한 후에 모델 클래스를 얻을 수 있습니다.
class ProblemSerializer(serializers.ModelSerializer):
def to_internal_value(self, data):
ModelClass = self.Meta.model
dfil = ModelClass._meta.get_field('date_update')
dfil.auto_now = False
dfil.editable = True
사용할 수 있는 솔루션이 필요했습니다.update_or_create
저는 @와 respelme 코드를 기반으로 이 솔루션에 도달했습니다.
유일한 변경 사항은 수정된 필드를 다음으로 설정하여 건너뛰기를 설정할 수 있다는 것입니다.skip
실제로 콰그를 통과하는 것뿐만 아니라skip_modified_update
저장 방법.
그저.yourmodelobject.modified='skip'
업데이트를 건너뜁니다!
from django.db import models
from django.utils import timezone
class TimeTrackableAbstractModel(models.Model):
created = models.DateTimeField(default=timezone.now, db_index=True)
modified = models.DateTimeField(default=timezone.now, db_index=True)
class Meta:
abstract = True
def save(self, *args, **kwargs):
skip_modified_update = kwargs.pop('skip_modified_update', False)
if skip_modified_update or self.modified == 'skip':
self.modified = models.F('modified')
else:
self.modified = timezone.now()
super(TimeTrackableAbstractModel, self).save(*args, **kwargs)
정확한 답은 아니지만(질문에 데이터 마이그레이션이 언급됨), 여기 파이테스트를 사용한 테스트 방법이 있습니다.
기본적으로 특정 필드 인스턴스 속성을 원숭이 패치하기 위한 고정 장치를 정의할 수 있습니다.예를 들어 필드 등을 순환하도록 조정할 수 있습니다.
@pytest.fixture
def disable_model_auto_dates(monkeypatch):
"""Disables auto dates on SomeModel."""
# might be local, might be on top
from project.models import SomeModel
field = SomeModel._meta.get_field('created_at')
monkeypatch.setattr(field, 'auto_now', False)
monkeypatch.setattr(field, 'auto_now_add', False)
다음은 https://stackoverflow.com/a/35943149/202168 의 유용한 답변에 대한 또 다른 변형과 단순화입니다.
이것은 여러 모델의 필드를 동시에 억제할 수 있습니다. - 와 함께 사용하면 유용합니다.factory_boy
예를 들어, 억제해야 하는 필드가 있는 SubFactory가 있는 경우
모양은 다음과 같습니다.
@contextmanager
def suppress_autonow(*fields: DeferredAttribute):
_original_values = {}
for deferred_attr in fields:
field = deferred_attr.field
_original_values[field] = {
'auto_now': field.auto_now,
'auto_now_add': field.auto_now_add,
}
field.auto_now = False
field.auto_now_add = False
try:
yield
finally:
for field, values in _original_values.items():
field.auto_now = values['auto_now']
field.auto_now_add = values['auto_now_add']
그리고 (와 함께)와 같이 사용됩니다.factory_boy
):
with suppress_autonow(Comment.created_at, Post.created_at):
PostFactory.create_batch(10) # if e.g. PostFactory also creates Comments
아니면 그냥 장고:
with suppress_autonow(FooBar.createtime, FooBar.lastupdatetime):
foobar = FooBar(
createtime=datetime(2013, 4, 6),
lastupdatetime=datetime(2016, 7, 9),
)
foobar.save()
즉, 억제하고자 하는 실제 필드에 합격하는 것입니다.
필드, )로 전달해야 합니다.Comment.created_at
및) 필드(not 턴스instance(not)my_comment.created_at
)
를 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " 이 .fields
괴롭힌다면, 하세요. 만약 그것이 당신을 괴롭힌다면, 여분을 추가하세요.isinstance
를뒤보 후에 합니다.field = deferred_attr.field
언급URL : https://stackoverflow.com/questions/7499767/temporarily-disable-auto-now-auto-now-add
'programing' 카테고리의 다른 글
인덱스별 Python 사전 요소 액세스 (0) | 2023.07.21 |
---|---|
Oracle에서 모든 외부 키, 제약 조건, 트리거 및 시퀀스가 업데이트되고 기존 데이터가 보존되도록 테이블 이름을 변경하려면 어떻게 해야 합니까? (0) | 2023.07.21 |
PEP 8, 키워드 인수 또는 기본 매개 변수 값에서 '=' 주변에 공백이 없는 이유는 무엇입니까? (0) | 2023.07.21 |
HTML 소스에 액세스하는 Python Selenium (0) | 2023.07.21 |
get_dummies(판다스)와 OneHotEncoder(Scikit-learn)의 장단점은 무엇입니까? (0) | 2023.07.21 |