Supongamos que tenemos un modelo
class BaseModel(models.Model): is_a = models.BooleanField()y dos modelos relacionados con este:
class A(models.Model): value_1 = models.IntegerField() base = models.ForeignKey(BaseModel, related_name='a') class B(models.Model): value_1 = models.IntegerField() value_2 = models.IntegerField() base = models.ForeignKey(BaseModel, related_name='b')Lo que necesito es referirme a A o B dependiendo de la propiedad is_a.
Por ejemplo,
base = BaseModel.objects.get(id=1) if base.is_a: obj = A.objects.create(value_1=1, base=base) else: obj = B.objects.create(value_1=1, value_2=2, base=base) return objo
if base.is_a: queryset = base.a.all() else: queryset = base.b.all() return querysetes decir, cada vez que tengo que verificar la propiedad is_a.
¿Hay manera más elegante?
Solo hay dos modelos relacionados, A y B, no aparecerán otros en un futuro próximo.
Parte del problema se puede resolver con django-polymorphic, por ejemplo:
class A(PolymorphicModel): ... class B(A): ... Esto permite recuperar todas las A y B con una solicitud como base.b.all() , pero el problema aquí es que cada B crea una instancia de A, que no es deseada.
También he considerado GenericForeignKey. Por lo que entendí, tiene una serie de limitaciones como "1) No puede usar GenericForeignKey en los filtros de consulta; 2) GenericForeignKey no aparecerá en un ModelForm" (de GenericForeignKey o ForeignKey ).
Una idea es agregar opciones al modelo base para tener una representación de cadena de su valor booleano. Si establece las cadenas iguales a los nombres de los modelos A y B, puede usar el método model.get_foo_display() para devolver el nombre del modelo. Luego use el método getattr() de Python para acceder a los atributos como variables.
class BaseModel(models.Model): base_model_choices = ( (True, 'A'), (False, 'B'), ) is_a = models.BooleanField(choices=base_model_choices)Por ejemplo,
base = BaseModel.objects.get(id=1) queryset = base.getattr(models, get_is_a_display()).all() obj = getattr(models, get_is_a_display()).objects.create(base=base)