djangodjango-modelsforeign-keys

How to access set of objects in reverse Foreign Key in Django


I have 2 tables defined like this:

class Optimization(BaseModel):
    name = models.TextField(unique=True, null=False)
    is_active = models.BooleanField(null=False, default=True)
    class Meta:
        db_table = 'optimization'


class OptimizationInput(BaseModel):
    name = models.TextField(null=False)
    optimization = models.ForeignKey(Optimization, null=False, on_delete=models.CASCADE)

    class Meta:
        db_table = 'optimization_input'

I want to get some Optimizations with their inputs. I can't figure out how to access the set of OptimizationInputs

I'm trying to do this:

optimizations = Optimization.objects.filter(is_active=True).only('name').values('name', 'optimizationinputs_set')

but I also tried this

optimizations = Optimization.objects.filter(is_active=True).first()
print('inputs', optimizations.optimizationinputs_set)

Either way, it tells me there is no such attribute as optimizationinputs_set


Solution

  • There is no sensible way to construct a nested object like that in SQL. Which is essentially what you are trying to do when you put the optimizationinput_set in values(). You have many options, but it depends on what you plan to do with the objects after your query them. The method that is closest to what I think you are asking for (a list of Optimisation instances with a nested list of OptimisationInputs) is to add a property to your Optimisation model that computes a list of OptimisationInputs. Something like the this:

    class Optimization(BaseModel):
        name = models.TextField(unique=True, null=False)
        is_active = models.BooleanField(null=False, default=True)
    
        class Meta:
            db_table = 'optimization'
    
        @property
        def optimization_input_list(self):
            return list(self.optimizationinput_set.all())
    
    
    class OptimizationInput(BaseModel):
        name = models.TextField(null=False)
        optimization = models.ForeignKey(Optimization, null=False, on_delete=models.CASCADE)
    
        class Meta:
            db_table = 'optimization_input'
    

    Then you can do

    optimizations = list(Optimization.objects.filter(is_active=True))
    

    Each optimization in this list will have access to optimization.optimization_input_list that will be a nested list of OptimizationInput instances. Just keep in mind that each time you call the optimization_input_list property will result in a new query to the database and a new nested list.

    If you wanted to included what you are trying to achieve with this I might be able give you a answer better suited to your use case.