2010-02-21 20 views
51

El Django docs solo muestra ejemplos para anular save() y delete(). Sin embargo, me gustaría definir algún procesamiento adicional para mis modelos solo cuando se creen. Para cualquiera que esté familiarizado con Rails, sería el equivalente a crear un filtro :before_create. es posible?Django - Anulando el método Model.create()?

Respuesta

102

Anulación de __init__() provocaría que el código se ejecutara siempre que se instanciara la representación en python del objeto. No sé los rieles, pero un filtro :before_created me parece que es un código que debe ejecutarse cuando el objeto se crea en la base de datos. Si desea ejecutar código cuando se crea un nuevo objeto en la base de datos, debe anular save(), verificando si el objeto tiene un atributo pk o no. El código sería algo como esto:

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) 
+5

De hecho, he encontrado una solución usando señales: http://docs.djangoproject.com/en/dev/topics/signals/ (la señal pre_save, específicamente). Sin embargo, esta parece ser una solución mucho más pragmática. Gracias un montón. – ground5hark

+0

buen truco. Todavía preferiría anular el método de crear porque me gustaría agregar una llamada a logging.info después de la creación de un nuevo objeto. Llamando antes y tienes la posibilidad de que falle la llamada al método principal ... – philgo20

+3

Supongo que quieres pasar por alto el método de administrador 'create'? Esa es una solución interesante, pero no funcionaría en los casos en los que el objeto se crea usando 'Object (** kwargs) .save()' o cualquier otra variación sobre eso. – Zach

4

Anulación __init__() le permitirá ejecutar código cuando se crea una instancia del modelo. No olvides llamar al padre __init__().

+0

Ah sí, esta fue la respuesta. No sé cómo pasé por alto esto. Gracias Ignacio. – ground5hark

17

un ejemplo de cómo crear una señal 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) 

aquí es una discusión seria sobre si lo mejor es utilizar señales o Reserva de encargo métodos http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/

En mi opinión, el uso de señales para esta tarea es más robusto, más fácil de leer pero más largo.

+0

Esta es la forma preferida en lugar de jugar con objetos internos, sin embargo, si realiza modificaciones en el modelo en cuestión, y no solo crea otro en el ejemplo anterior, ** no olvide llamar a 'instance.save()' **. Entonces, en este caso, también hay una penalización de rendimiento ya que habrá una consulta INSERT y una UPDATE en la base de datos. –

1

Para responder a la pregunta, literalmente, el método create en el administrador de un modelo es una forma estándar de crear objetos nuevos en Django. Para anular, hacer algo como

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() 

En este ejemplo, estoy anulando método método create del gerente para hacer algún procesamiento adicional antes de que realmente se crea la instancia.

NOTA: código como

my_new_instance = MyModel.objects.create(my_field='my_field value')

va a ejecutar este método modificado create, pero el código como

my_new_unsaved_instance = MyModel(my_field='my_field value')

no lo hará.

3

Esto es viejo, tiene una respuesta aceptada que funciona (Zach), y una más idiomática también (Michael Bylstra), pero como sigue siendo el primer resultado en Google la mayoría de la gente ve, Creo que necesitamos una mejor -practices estilo moderno-respuesta Django aquí:

El punto es el siguiente:

  1. señales de uso (leer más)
  2. utilizan un método para agradable n amespacing (si tiene sentido) ... y me marcó como @classmethod en lugar de @staticmethod porque lo más probable que va a terminar necesidad de referirse miembros de la clase estática en el código

aún más limpio sería si núcleo de Django tener una señal real post_create. (Imho si necesita pasar un argumento booleano para cambiar el comportamiento de un método, deberían ser 2 métodos).