简体   繁体   中英

Get reverse relationship for item in a list of dictionaries

I have a list (QuerySet of 'DailyEnrollment' objects) of dictionaries that looks like this:

[
{'location_id': 1, 'student_count': 780}, 
{'location_id': 4, 'student_count': 535}, 
{'location_id': 6, 'student_count': 496}
]

There is a Location object which has an attribute name - the location_id in this list, correlates to a Location object but it is not a foreign key (in the models) due to how other apps interact with this in our project.

Is there a simple way to iterate across this list, get each dictionaries location.name for the location_id and append it to the dictionary as location_name ?

I was considering a dictionary comprehension inside of a list comprehension - but I wasn't sure how Pythonic that was.

Models:

class Location(models.Model):
    name = models.CharField(max_length=50)
    short_name = models.CharField(max_length=50)

The DailyEnrollment is data nabbed from a view built with external data

class DailyEnrollment(SchoolModel):
    id            = models.IntegerField(db_column='ID', primary_key=True)
    location_id   = models.IntegerField(db_column='schoolID')
    grade         = models.CharField(db_column='grade', max_length=10)
    end_year      = models.IntegerField(db_column='endYear')
    run_date      = models.DateField(db_column='runDate')
    student_count = models.IntegerField(db_column='studentCount')

In the view this is how I get my Daily Enrollments

# get past enrollments
    past_daily_enrollments = DailyEnrollment.objects.filter(
                run_date=datetime.strptime(since_date, '%m-%d-%Y'),
                location_id__lte='31',
                end_year='2018')

I create a 'new list' of data with everything grouped on location_id , with the total student_count

location_data = past_daily_enrollments.values('location_id').annotate(
    student_count=Sum('student_count')
)

That's how I get to the issue I asked about. I have 'location_data', which is my list of dictionaries.

Your models are not correct. I suspect that they were produced by running inspectdb against an existing database; one of the issues with doing that is that it is occasionally unable to detect foreign keys. In your case however, location_id is clearly a foreign key to Location, so you should declare it as such:

location = models.ForeignKey('Location', db_column='schoolID')

Once you have done that, you can simply follow the relationship via the double-underscore syntax in your values call:

past_daily_enrollments.values('location__name')...

So (for the time being) I went about manually reconciling them through a few steps.

First I use my location data and get a list of all the ID's like this:

location_ids   = [s['location_id'] for s in location_data]

Then I get the Location objects for those ID's:

location_items = Location.objects.filter(
        id__in=location_ids
    )

Then I make a small dictionary with the ID and the name:

location_names = [
        {'location_id':s.id, 'location_name': s.name}
        for s in location_items
    ]

Then I chain the two lists of dictionaries together and and create a new one from them based on the 'location_id' tying each dictionary together.

additional_location_data  = defaultdict(dict)
for d in chain(past_enrollments, location_names):
    additional_location_data[d['location_id']].update(d)

This worked to reconcile the location_id with the name of the Location object and put the name in a dictionary (inside of a list) in the appropriate spots.

It's probably fairly 'ugly' for now - but I'll worry about cleaning it up later.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM