A documentação do Django apenas lista exemplos para sobrescrever save()
e delete()
. No entanto, gostaria de definir algum processamento extra para meus modelos apenas quando eles forem criados . Para qualquer pessoa familiarizada com Rails, seria o equivalente a criar um :before_create
filtro. Isso é possível?
fonte
create
? Essa é uma solução interessante, mas não funcionaria nos casos em que o objeto está sendo criado usandoObject(**kwargs).save()
ou qualquer outra variação dele.super(MyModel, self).save(*args, **kwargs)
?self.pk
não seja a melhor opção para verificar se o objeto está sendo criado recentemente ou apenas atualizando. Às vezes, você fornece o id do objeto no momento da criação (um valor personalizado não gerado pelo banco de dados comoKSUID
), e isso fará com que esta cláusula nunca seja executada ... Háself._state.adding
valor para ter certeza se está salvando pela primeira vez ou apenas atualizando, que ajuda nesses casos.um exemplo de como criar um sinal post_save (de 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)
aqui está uma discussão cuidadosa sobre se é melhor usar sinais ou métodos de salvamento personalizados https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/ django-signs-vs-custom-save-method /
Na minha opinião, usar sinais para esta tarefa é mais robusto, fácil de ler, mas mais demorado.
fonte
instance.save()
. Portanto, neste caso, também há uma penalidade de desempenho, pois haverá uma consulta INSERT e uma UPDATE no banco de dados.Isso é antigo, tem uma resposta aceita que funciona (de Zach) e também mais idiomática (de Michael Bylstra), mas como ainda é o primeiro resultado no Google que a maioria das pessoas vê, acho que precisamos de um django moderno com mais práticas recomendadas resposta de estilo aqui :
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)
O ponto é este:
@classmethod
vez de@staticmethod
porque muito provavelmente você acabará precisando referir-se aos membros da classe estática no códigoAinda mais limpo seria se o Django central tivesse um
post_create
sinal real . (Imho, se você precisar passar um argumento booleano para alterar o comportamento de um método, isso deve ser 2 métodos.)fonte
Para responder à pergunta literalmente, o
create
método em um gerenciador de modelo é uma forma padrão de criar novos objetos no Django. Para substituir, faça algo comofrom 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()
Neste exemplo, estou substituindo o método do método Manager
create
para fazer algum processamento extra antes que a instância seja realmente criada.NOTA: Codifique como
my_new_instance = MyModel.objects.create(my_field='my_field value')
irá executar este
create
método modificado , mas o código comomy_new_unsaved_instance = MyModel(my_field='my_field value')
não vou.
fonte
A substituição
__init__()
permitirá que você execute o código quando o modelo for instanciado. Não se esqueça de ligar para os pais__init__()
.fonte
Você pode substituir o método de criação com um gerenciador personalizado ou adicionar um método de classe na classe do modelo. https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects
fonte
A resposta preferida está correta, mas o teste para saber se o objeto está sendo criado não funciona se seu modelo deriva de UUIDModel. O campo pk já terá um valor.
Nesse caso, você pode fazer o seguinte:
already_created = MyModel.objects.filter(pk=self.pk).exists()
fonte