0

I want to add extra field which with value from 2nd level of related model. the problem is because the first level is one to many.

example Models:

class ModelA(BaseModel):
    name=models.CharField()

class ModelB(BaseModel):
    type=models.CharField(max_length=100, unique=True) #the value will be one of [x, y, z]
    parent = models.ForeignKey('ModelA', related_name='related_models')

class ModelC(BaseModel):
    ext = models.CharField(max_length=100, unique=True)
    model_b = models.ForeignKey('ModelB', related_name='modelc')

example values of models

modelA = [
    {'id': 1,'name': 'data1'},
    {'id': 2,'name': 'data2'},
    {'id': 3,'name': 'data3'},
    {'id': 4,'name': 'data4'}
]

modelB = [
    {'id': 1,'type': 'y', 'parent_id': 1},
    {'id': 2,'type': 'z', 'parent_id': 1},
    {'id': 3,'type': 'x', 'parent_id': 3},
    {'id': 4,'type': 'z', 'parent_id': 3},
    {'id': 5,'type': 'z', 'parent_id': 2},
]

modelC = [
    {'id': 1, 'ext': 'juststr#1', 'model_b_id': 2},
    {'id': 2, 'ext': 'juststr#2', 'model_b_id': 4},
]

expected output:

[
    {'id': 1,'name': 'data1', 'mc_status': True},
    {'id': 2,'name': 'data2', 'mc_status': False},
    {'id': 3,'name': 'data3', 'mc_status': True},
    {'id': 4,'name': 'data4', 'mc_status': False}
]

I've tried:

model_a = model_a.annotate(
    mc_status=Case(
        When(
            Q('related_models__type'='z', 'related_models__modelc__isnull'=False),
            then=True
        ),
        default=Value(False),
        output_field=BooleanField()
    )
)
#wrong result :(

I don't know if the method I'm trying is correct or not, but obviously the result is wrong. I though its because the second level of the relationship between modelA to modelC tables is not one to one. if anyone knows how or have a reference it would be very useful thanks.|

update: finally I solve this problem, and the solution is

subquery_mb = ModelB.objects.filter(parent_id=OuterRef('pk'), modelc__isnull=False)
model_a = model_a.annotate(
    mc_status=Exists(subquery_mb)
)

#this code is not tested and not exactly same with the real implemented code but same solution

0 Answers0