0

I have 3 models:

class Country(models.Model):
    country_id = models.AutoField(primary_key=True)
    country_name = models.CharField(max_length=50)
    population = models.BigIntegerField()

class State(models.Model):
    state_id = models.AutoField(primary_key=True)
    state_name = models.CharField(max_length=50)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    population = models.BigIntegerField()

class District(models.Model):
    state_id = models.AutoField(primary_key=True)
    district_name = models.CharField(max_length=50)
    state = models.ForeignKey(State, on_delete=models.CASCADE)
    population = models.BigIntegerField()

Now given a country_id, I want to fetch all the related State and District in following format:

{
    'country':{
        'country_id': 1,
        'coutry_population': 120000,
        'state':[
            {
            'state_id': 10,
            'state_name': 'A',
            'state_population': 10000,
            'district':[
                {
                    'district_id': 100,
                    'district_name': 'District1',
                    'district_population': 4000
                },
                {
                    'district_id': 101,
                    'district_name': 'District2',
                    'district_population': 6000
                }]
            },
            {
                <2nd state data here>
            }
        ]
    }
}

Also I should be able select particular columns from each of the model.

For Eg: Only state_name from State Model, district_name and district_population from District Model, etc

I also need the feature of filtering, at different models.

For eg: Only get districts matching condition district.population > 5000

None of the question I could find here helped to solve the problem. Closest one seemed to be this : Django: Most efficient way to create a nested dictionary from querying related models?

But here the relationship is in opposite direction.

One solution I could think of was to query each of the models differently, and store them in dictionary, and combine later. But if I could get more of a direct approach, that would be helpful.

ezvine
  • 751
  • 1
  • 8
  • 23

1 Answers1

0

There is no need to manually glue together a dictionary with the required data.

You can query the country object and get the the related districts through the related manager.

my_country = Country.objects.get(1)
all_districts = my_country.district_set.all()

Or filtered districts:

filtered_districts = my_country.district_set.filter(district_name='...')

You can also set a related_name in the Model class eg:

class State(models.Model):
    state_id = models.AutoField(primary_key=True)
    state_name = models.CharField(max_length=50)
    country = models.ForeignKey(Country, on_delete=models.CASCADE, related_name = 'states')
    population = models.BigIntegerField()

Then you can query the related states with:

large_states_of_my_country = my_country.states.filter(population_gte = 50000)

See:

Ali
  • 761
  • 1
  • 5
  • 24
  • This is certainly helpful. But even with this, I cannot get the data in the structure I want right ? I need the dictionary in structure `country->state->district` as mentioned in question. This query will give me all the districts under the country. But I want it all state-wise. And also some data from state table, as shown in the example in question. – ezvine May 28 '20 at 14:36
  • There is another related manager for the state objects. So if you need to access all the districts for a given state you can just do state.district_set.all(). E.g. `for state in large_states_of_my_country: districts_of_state = state.district_set.all() ...` – Ali May 28 '20 at 20:51