tutorial tipos modelo example eliminar consultas campos avanzadas python django django-models django-1.2

python - tipos - Django Model Field predeterminado basado en otro campo en el mismo modelo



tutorial django 2 (4)

¡Los modelos ciertamente tienen un "yo"! Es solo que estás tratando de definir un atributo de una clase de modelo como dependiente de una instancia modelo; eso no es posible, ya que la instancia no (y no puede) existir antes de definir la clase y sus atributos.

Para obtener el efecto que desea, anule el método save () de la clase de modelo. Haga los cambios que desee a la instancia necesaria, luego llame al método de la superclase para hacer el ahorro real. Aquí hay un ejemplo rápido.

def save(self, *args, **kwargs): if not self.subject_init: self.subject_init = self.subject_initials() super(Subject, self).save(*args, **kwargs)

Esto se cubre en Métodos de modelos superiores en la documentación.

Tengo un modelo que me gustaría incluir el nombre de un sujeto y sus iniciales. (Los datos se anonimizan un tanto y se siguen sus iniciales).

En este momento, escribí

class Subject(models.Model): name = models.CharField("Name", max_length=30) def subject_initials(self): return ''''.join(map(lambda x: '''' if len(x)==0 else x[0], self.name.split('' ''))) # Next line is what I want to do (or something equivalent), but doesn''t work with # NameError: name ''self'' is not defined subject_init = models.CharField("Subject Initials", max_length=5, default=self.subject_initials)

Como lo indica la última línea, preferiría que las iniciales se almacenaran en la base de datos como un campo (independiente del nombre), pero se inicializa con un valor predeterminado basado en el campo de nombre. Sin embargo, tengo problemas ya que los modelos django no parecen tener un "yo".

Si cambio la línea a subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials) , puedo hacer el syncdb, pero no puedo crear nuevos temas.

¿Es esto posible en django, tener una función invocable dar un valor predeterminado a un campo basado en el valor de otro campo?

(Para los curiosos, la razón por la que quiero separar las iniciales de mi tienda por separado es en casos excepcionales en que los apellidos extraños pueden ser diferentes a los que estoy rastreando. Por ejemplo, alguien más decidió que las iniciales del sujeto 1 con el nombre "John O''Mallory" son "JM" en lugar de "JO" y quiere corregirlo edítelo como administrador).


Como una implementación alternativa de la respuesta de , también puede conectarse a la señal pre_save utilizando el decorador del receiver :

from django.db.models.signals import pre_save from django.dispatch import receiver @receiver(pre_save, sender=Subject) def default_subject(sender, instance, **kwargs): if not instance.subject_init: instance.subject_init = instance.subject_initials()

Esta función de receptor también toma los argumentos de la palabra clave comodín **kwargs que todos los manejadores de señal deben tomar de acuerdo con docs.djangoproject.com/en/2.0/topics/signals/… .


No sé si hay una forma mejor de hacerlo, pero puedes usar un manejador de señal para la señal pre_save :

from django.db.models.signals import pre_save def default_subject(sender, instance, using): if not instance.subject_init: instance.subject_init = instance.subject_initials() pre_save.connect(default_subject, sender=Subject)


Usando las señales de Django , esto puede hacerse bastante temprano, al recibir la señal de post_init del modelo.

from django.db import models import django.dispatch class LoremIpsum(models.Model): name = models.CharField( "Name", max_length=30, ) subject_initials = models.CharField( "Subject Initials", max_length=5, ) @django.dispatch.receiver(models.signals.post_init, sender=LoremIpsum) def set_default_loremipsum_initials(sender, instance, *args, **kwargs): """ Set the default value for `subject_initials` on the `instance`. :param sender: The `LoremIpsum` class that sent the signal. :param instance: The `LoremIpsum` instance that is being initialised. :return: None. """ if not instance.subject_initials: instance.subject_initials = "".join(map( (lambda x: x[0] if x else ""), instance.name.split(" ")))

La post_init señal post_init una vez que ha hecho la inicialización en la instancia. De esta forma, la instancia obtiene un valor para el name antes de probar si sus campos no anulables están configurados.