Opened 9 years ago

Closed 8 years ago

#3369 closed (duplicate)

reverse caching of foreign keys

Reported by: wbyoung@… Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Keywords:
Cc: ferringb@… Triage Stage: Design decision needed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

It would be nice if Django were to cache the reverse value of foreign keys when they're looked up. That might not be entirely clear, so let me give an example:

class Company(Model):
    name = models.CharField(maxlength=100)

class Employee(Model):
    company = models.ForeignKey(Company)


c = Company.objects.all()[0]
e = c.employee_set.all()[0]

# e now really must have a company of c... there's no reason it wouldn't be c
e.company # accesses the database

I tried implementing this, but got lost in some of the model code. My approach was to use an auto_cache 'filter' for QuerySets. The above code would look like this:

c = Company.objects.all()[0]
e = c.employee_set.auto_cache(company=c).all()[0]

e.company # no database accesses

Which eventually I would have made automatic for all sets. I got far enough to realize that each foreign key will potentially query the database even after an attribute has explicitly been assigned. For example:

c = Company.objects.all()[0]
e = c.employee_set.all()[0]

new_company = Company()
e.company = new_company
e.company == new_company # database accesses for e.company and not equal to the new object

I'd love to see a feature like this, so if it's not something that you all want to implement, point me in the right direction.

Attachments (2)

patch_1.diff (4.0 KB) - added by wbyoung@… 9 years ago.
patch_2.diff (5.5 KB) - added by wbyoung@… 9 years ago.

Download all attachments as: .zip

Change History (9)

comment:1 Changed 9 years ago by wbyoung@…

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Sorry, that last bit was wrong. It should have been as follows:

c = Company.objects.all()[0]
e = c.employee_set.all()[0]

e.company = c
e.company is c # database accesses for e.company and not equal to the new object

So I guess that the reason that e.company isn't being updated is because the foreign key is equal to c's primary key. It appears to work fine in other cases, though.

It seems that this aspect of it could either be considered a 'feature' or a 'bug'. Either functionality seems to be right in some sense, but for the auto_cache to work it would have to be a bug.

comment:2 Changed 9 years ago by Michael Radziej <mir@…>

  • Component changed from Uncategorized to Database wrapper
  • Owner changed from jacob to adrian
  • Triage Stage changed from Unreviewed to Design decision needed

Ah, a idea like this should be brought up on the developers list. I like it! Can you do, please?

Changed 9 years ago by wbyoung@…

comment:3 Changed 9 years ago by wbyoung@…

  • Has patch set
  • Needs documentation set
  • Patch needs improvement set

I've implemented it. I'm going to work on making it automatic now, but the auto_cache part works. I'm attaching a patch.

Changed 9 years ago by wbyoung@…

comment:4 Changed 9 years ago by wbyoung@…

  • Needs documentation unset
  • Patch needs improvement unset

Patch 2 makes it automatic. With review this should be ready to add into the trunk. It seems to work very nicely.

comment:5 follow-up: Changed 8 years ago by (removed)

  • Cc ferringb@… added

Examples provided in patch2 makes me suspect this is more generally provided by ticket #17... correct assumption?

comment:6 Changed 8 years ago by wbyoung@…

They're not exactly the same thing, but I think the fixes to #17 would fix this as well.

comment:7 in reply to: ↑ 5 Changed 8 years ago by ubernostrum

  • Resolution set to duplicate
  • Status changed from new to closed

Replying to Brian Harring <ferringb@gmail.com>:

Examples provided in patch2 makes me suspect this is more generally provided by ticket #17... correct assumption?

Yes. Closing this in favor of #17.

Note: See TracTickets for help on using tickets.
Back to Top