Opened 18 years ago

Closed 17 years ago

#2684 closed defect (worksforme)

[patch] Backwards relations (ie. xxx_set) across different apps needs voodoo magic to work

Reported by: parlar@… Owned by: oggie_rob
Component: Core (Other) Version: dev
Severity: normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

As described (and temporarily solved) here: http://groups.google.com/group/django-users/browse_frm/thread/8b1f9699dd5c72d1/2663f422db6a027c?lnk=arm#2663f422db6a027c

In general, I have a Photo model and an Article model. They live in separate applications. The Article model has:
picture = models.ForeignKey(Photo)

The problem is that you can't access the 'article_set' attribute from a Photo instance *unless* you've already imported 'Article'.

Russell says that this is reasonably obvious if you know the internals, but it's definitely not documented.

So this should be properly documented, and if anyone can figure out how, a fix should be put in so you don't need to import the 'Article' model just to be able to access 'article_set' on a Photo instance.

Attachments (1)

2684.patch (1.2 KB ) - added by Russell Keith-Magee 18 years ago.
Patch to force caching of related objects

Download all attachments as: .zip

Change History (9)

comment:1 by parlar@…, 18 years ago

Update:

If you do the following:

'Photo.objects.all()[0].article_set.all()' without importing 'Article', you will get an AttributeError on 'article_set'.

However, if you do this instead:

'Photo.objects.get(id=1).article_set.all()' without importing 'Article', the 'article_set' attribute works perfectly!

by Russell Keith-Magee, 18 years ago

Attachment: 2684.patch added

Patch to force caching of related objects

comment:2 by Russell Keith-Magee, 18 years ago

Owner: changed from Adrian Holovaty to Russell Keith-Magee
Status: newassigned
Summary: Backwards relations (ie. xxx_set) across different apps needs voodoo magic to work[patch] Backwards relations (ie. xxx_set) across different apps needs voodoo magic to work
Version: SVN

The attached patch fixes the problem; commit pending the lifting of the moratorium on django.db.models development.

comment:3 by Russell Keith-Magee, 18 years ago

To clarify the exact problem; If you have a model A with a ForiegnKey/M2M relation on model B, and your code is:

from test.project.models import B
objs = B.objects.all()

the members of objs don't have their related descriptors (e.g., b.a_set) instantiated. This is because the related models are never imported, so the contribute_to_class methods for the related classes are never called.

A single call to B.objects.get(), B.objects.filter(), or just about anything else that interacts with fields will call the _meta.get_all_related_objects() and _meta.get_all_related_many_to_many_objects() methods to be called, which causes these methods to fill their caches, which causes the related models to be imported, and the related descriptors to be created.

Simple workaround, demonstrated in the patch - force the creation of an object instance to cause the meta class instance to populate its caches.

comment:4 by Russell Keith-Magee, 18 years ago

I should clarify - this isn't anywhere close to an ideal fix; I'm actually against applying it to trunk. However, it is a rough workaround, and gives a vague indication where the problem lies.

comment:5 by Malcolm Tredinnick, 18 years ago

Looks like #2416 contains another side-effect of this.

comment:6 by Chris Beaven, 18 years ago

Patch needs improvement: set
Triage Stage: UnreviewedAccepted

comment:7 by oggie_rob, 17 years ago

Owner: changed from nobody to oggie_rob
Status: assignednew

I think this can be closed now. I tested it out and it seems to work without importing the backward-related field.

comment:8 by Russell Keith-Magee, 17 years ago

Resolution: worksforme
Status: newclosed

Looks like this problem has been fixed by the model loading refactor.

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