장고 문서는 단지 오버라이드 (override)에 대한 예제 목록 save()
과 delete()
. 그러나 모델 이 생성 될 때만 모델에 대한 추가 처리를 정의하고 싶습니다 . Rails에 익숙한 사람이라면 :before_create
필터 를 만드는 것과 같습니다 . 이것이 가능한가?
장고 문서는 단지 오버라이드 (override)에 대한 예제 목록 save()
과 delete()
. 그러나 모델 이 생성 될 때만 모델에 대한 추가 처리를 정의하고 싶습니다 . Rails에 익숙한 사람이라면 :before_create
필터 를 만드는 것과 같습니다 . 이것이 가능한가?
답변:
재정의 __init__()
하면 객체의 파이썬 표현이 인스턴스화 될 때마다 코드가 실행됩니다. 레일을 모르지만 :before_created
데이터베이스에서 개체가 생성 될 때 실행되는 코드처럼 필터가 들립니다. 데이터베이스에 새 객체가 생성 될 때 코드를 실행 save()
하려면 객체에 pk
속성 이 있는지 여부를 확인 하여을 재정의해야합니다 . 코드는 다음과 같습니다.
def save(self, *args, **kwargs):
if not self.pk:
# This code only happens if the objects is
# not in the database yet. Otherwise it would
# have pk
super(MyModel, self).save(*args, **kwargs)
create
합니까? 이것은 흥미로운 솔루션이지만 객체가 생성되는 경우 Object(**kwargs).save()
또는 다른 변형을 사용하는 경우에는 작동하지 않습니다 .
super(MyModel, self).save(*args, **kwargs)
그래?
self.pk
객체가 새로 생성되는하거나 업데이트되어 있는지 확인하는 가장 좋은 옵션이 아닙니다. 때로는 생성 시간에 개체 ID (예 : 사용자 지정 비 데이터베이스 생성 값 KSUID
)를 제공하면이 절이 실행되지 않습니다 ... self._state.adding
처음으로 저장하는지 아니면 업데이트 만하는지 확인하는 값이 있습니다. 이러한 경우에 도움이됩니다.
post_save 신호를 생성하는 방법의 예 ( http://djangosnippets.org/snippets/500/에서 )
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
"""Create a matching profile whenever a user object is created."""
if created:
profile, new = UserProfile.objects.get_or_create(user=instance)
다음은 신호 또는 사용자 지정 저장 방법을 사용하는 것이 가장 좋은지에 대한 신중한 토론입니다. https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/ django-signals-vs-custom-save-method /
제 생각에는이 작업에 신호를 사용하는 것이 더 강력하고 읽기 쉽지만 더 길다고 생각합니다.
instance.save()
. 따라서이 경우 데이터베이스에 대한 INSERT 및 UPDATE 쿼리가 하나씩 있기 때문에 성능이 저하됩니다.
이것은 오래되었고 작동하는 대답 (Zach 's)과 좀 더 관용적 인 대답 (Michael Bylstra 's)도 가지고 있지만 여전히 대부분의 사람들이 Google에서 보는 첫 번째 결과이기 때문에 더 많은 모범 사례 modern-django가 필요하다고 생각합니다. 여기 스타일 대답 :
from django.db.models.signals import post_save
class MyModel(models.Model):
# ...
@classmethod
def post_create(cls, sender, instance, created, *args, **kwargs):
if not created:
return
# ...what needs to happen on create
post_save.connect(MyModel.post_create, sender=MyModel)
요점은 다음과 같습니다.
@classmethod
대신 @staticmethod
코드에서 정적 클래스 멤버를 참조해야 할 가능성이 높기 때문에 대신 표시했습니다.핵심 Django가 실제 post_create
신호를 가지고 있다면 더 깨끗할 것 입니다. (메소드의 동작을 변경하기 위해 부울 인수를 전달해야하는 경우 Imho는 2 개의 메서드 여야합니다.)
문자 그대로 질문에 답하기 위해 create
모델 관리자 의 메서드는 Django에서 새 개체를 만드는 표준 방법입니다. 재정의하려면 다음과 같이하십시오.
from django.db import models
class MyModelManager(models.Manager):
def create(self, **obj_data):
# Do some extra stuff here on the submitted data before saving...
# For example...
obj_data['my_field'] = my_computed_value(obj_data['my_other_field'])
# Now call the super method which does the actual creation
return super().create(**obj_data) # Python 3 syntax!!
class MyModel(models.model):
# An example model
my_field = models.CharField(max_length=250)
my_other_field = models.CharField(max_length=250)
objects = MyModelManager()
이 예에서는 create
인스턴스가 실제로 생성되기 전에 몇 가지 추가 처리를 수행하기 위해 Manager의 메서드 메서드를 재정의합니다 .
참고 : 다음 과 같은 코드
my_new_instance = MyModel.objects.create(my_field='my_field value')
이 수정 된 create
메서드 를 실행 하지만 다음과 같은 코드
my_new_unsaved_instance = MyModel(my_field='my_field value')
하지 않을 것이다.
재정의 __init__()
하면 모델이 인스턴스화 될 때 코드를 실행할 수 있습니다. 부모에게 전화하는 것을 잊지 마십시오 __init__()
.
사용자 지정 관리자로 create 메서드를 재정의하거나 모델 클래스에 클래스 메서드를 추가 할 수 있습니다. https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects