Django получает дочерний объект через родительский

#python #django #django-models

#python #django #django-модели

Вопрос:

Я пытался получить доступ к дочернему объекту через родительский объект, поскольку я хочу выполнять разные операции в зависимости от типа объекта. Что у меня есть, так это:

 #models.py
class A(models.Model):
    ...

class B(A):
    field1 = models.CharField(...)
    ...

class C(A):
    field2 = models.IntegerField(...)
  

Я мог бы выполнить 2 цикла for и выполнить то, что я хочу:

 for obj in B.objects.all():
    if field1 == 'something':
        do some operation

for obj in C.objects.all():
    if field2 == 5:
        do some other operation
  

Но я подумал, разве невозможно сделать это с помощью цикла 1 for и получить доступ к дочернему объекту через родительский?

 for obj in A.objects.all():
    if obj.b and obj.b.field1 == 'something':
        do some operation
    elif obj.c and obj.c.field2 == 5:
        do some other operation
  

Я также подумал, что select_related может помочь, но там сказано, что это работает только для ForeignKey .

Более того, я надеялся сделать это без использования дополнительных приложений, таких как django-model-utils или django-polymorphic, потому что я чувствую, что для этого должна быть простая операция запроса.

Комментарии:

1. Я немного запутался в вашем запросе, но у меня аналогичный вопрос. если obj.b и obj.b.field1 == ‘something’: у obj нет атрибута «b», у obj.c и obj.c.field2 obj также нет атрибута «c»

Ответ №1:

Вы можете перейти к дочернему объекту из родительского, как вы делали в последнем цикле for, но вам также нужно будет проверить, существует ли дочерний объект для родительского, например:

 for obj in A.objects.all():
    try:
        if obj.b.field1 == 'something':
            do some operation
    except ObjectDoesNotExist:
        # obj does not have a child of class B

    try:
        if obj.c.field2 == 5:
            do some other operation
    except ObjectDoesNotExist:
        # obj does not have a child of class C
  

Вы также можете объединить это в один запрос, используя Q objects:

 A.objects.filter(Q(b__isnull=False, b__field1='something') | Q(c__isnull=False, c__field2=5))
  

Это вернет объекты класса A

Ответ №2:

Возможно, это может быть кому-то полезно. hasattr в противном случае True будет возвращен False для правильного дочернего экземпляра. Пожалуйста, обратите внимание, что имя класса указано в smallcase для hasattr параметра.

 for obj in A.objects.all():
    if obj.hasattr('b'):
       # do something specific to b
    if obj.hasattr('c'):
       # do something specific to c