Backwards relation (ie XXX_set) across apps

17 views
Skip to first unread message

Jay Parlar

unread,
Sep 6, 2006, 11:49:36 PM9/6/06
to django...@googlegroups.com
In my project, I have a photo gallery app (stockphoto, to be precise),
as well as an 'articles' app. The basic layout is that in the photo
gallery app, I have:

class Photo(models.Model):
image = models.ImageField(...)
etc. etc.


In the 'articles' app, I have the following:

from myproject.stockphoto.models import Photo

class Article(models.Model):
title = models.CharField(maxlength=200, unique=True)
slug = models.SlugField(prepopulate_from=['title'])
body = models.TextField()
picture = models.ForeignKey(Photo, blank=True,null=True)


In the Admin, everything works fine and dandy. When adding new
Articles, I can either point them at existing pictures, or add new
pictures.

And instances of 'Article' do what you would expect.

Instances of 'Photo' do not though. I *should* be able to do something like:

>>> x = Photo.objects.all()[0]
>>> articles = x.article_set.all()

(I want to be able to find all the articles a given picture has been used in).

This is decidedly not working. The reason being is that my instances
of Photo *never* have an 'article_set' attribute.

The only reason I can guess is that because the two models are defined
in separate applications.

Am I missing something here?

Jay P.

PS. An interesting (and perhaps related) sidenote: In my
INSTALLED_APPS, I *have* to have the 'stockphoto' app appear before
the 'articles' app, otherwise I get the following when trying to
import 'Article' in IPython:

ImportError: No module named model

Russell Keith-Magee

unread,
Sep 8, 2006, 6:13:27 AM9/8/06
to django...@googlegroups.com
On 9/7/06, Jay Parlar <par...@gmail.com> wrote:

The only reason I can guess is that because the two models are defined
in separate applications.

Am I missing something here?

I just tried the following in a test project;

testproject/mytest/models.py:------------
from django.db import models

class Image(models.Model):
    name = models.CharField(maxlength=20)
testproject/mytest2/models.py-----------
from django.db import models
from testproject.mytest.models import Image

class Article(models.Model):
    name = models.CharField (maxlength=20)
    img = models.ForeignKey(Image)

---

Then, add both apps to INSTALLED_APPS, sync, and in a shell:

>from testproject.mytest.models import Image
>from testproject.mytest2.models import Article

>img1 = Image(name='foo')
>img1.save()

>art1 = Article(name='bar', img=img1)
>art1.save()

>img1 = Image.objects.all()[0]
>print img1.article_set.all()

returns [<Article: Article object>] as expected. Do you get the same result if you use this project?

Can you provide any more details about you application?

The only reason I can think that you wouldn't get a _set descriptor is in the case of a m2m relation to self.

PS. An interesting (and perhaps related) sidenote: In my
INSTALLED_APPS, I *have* to have the 'stockphoto' app appear before
the 'articles' app, otherwise I get the following when trying to
import 'Article' in IPython:

ImportError: No module named model

This is an reference resolution problem; Article references Photo, so Photo needs to be defined first.

Yours,
Russ Magee %-)

Jay Parlar

unread,
Sep 8, 2006, 10:33:20 AM9/8/06
to django...@googlegroups.com

Well, from the shell, it seems to work like a charm. It only seems to
broken at the Admin level.

My Photo model is here:
http://svn.jayparlar.com/website/trunk/awwca/stockphoto/models.py
(This is almost identical to the models.py that ships with the
'stockphoto' application)

My Article model is here:
http://svn.jayparlar.com/website/trunk/awwca/articles/models.py
(Although for these tests today, I stripped out all the fields except
'title' and 'picture')

Here's what I tried: Added a Photo and Article from the admin. In the
shell, there was no 'article_set' attribute.

However, staying in the shell, I created (and saved) a *new* Article
instance, giving it the Picture instance that was created in the
Admin. After that, I *would* have an 'article_set' attribute, that
would show both the Article created in the Admin, and the one created
in the shell.


Jay P.

Steven Armstrong

unread,
Sep 8, 2006, 12:33:07 PM9/8/06
to django...@googlegroups.com

Hi Jay

I had a similar problem recently. It turned out to have something to do
with the blank=True and null=True arguments.

picture = models.ForeignKey(Photo, blank=True,null=True)

Maybe, for testing, try removing those and see it the article_set is
available as expected without them.

picture = models.ForeignKey(Photo)

If it is, it may be a bug in django.

I don't know if this is really related to your problem, just thought
I'll drop a note here as the symptoms sound familiar.

Jay Parlar

unread,
Sep 8, 2006, 2:06:47 PM9/8/06
to django...@googlegroups.com
On 9/9/06, Steven Armstrong <s...@c-area.ch> wrote:
>
> I had a similar problem recently. It turned out to have something to do
> with the blank=True and null=True arguments.
>
> picture = models.ForeignKey(Photo, blank=True,null=True)
>
> Maybe, for testing, try removing those and see it the article_set is
> available as expected without them.
>
> picture = models.ForeignKey(Photo)
>
> If it is, it may be a bug in django.
>
> I don't know if this is really related to your problem, just thought
> I'll drop a note here as the symptoms sound familiar.

No such luck, I'm still seeing the problem. I appreciate the thought though!

Jay P.

Jay Parlar

unread,
Sep 8, 2006, 2:26:03 PM9/8/06
to django...@googlegroups.com
I wonder if this is somehow related. From the db_api documentation, in
the "How are the backward relationships possible?" section, it states:


"The answer lies in the INSTALLED_APPS setting. The first time any
model is loaded, Django iterates over every model in INSTALLED_APPS
and creates the backward relationships in memory as needed.
Essentially, one of the functions of INSTALLED_APPS is to tell Django
the entire model domain."

Because 'stockphoto' appears before 'articles' in INSTALLED_APPS,
could it be preventing the ORM from seeing the 'Article' model?

That doesn't feel quite right, simply because someone would have hit
it before this, but it's a possibility.

Jay P.

Russell Keith-Magee

unread,
Sep 8, 2006, 10:43:58 PM9/8/06
to django...@googlegroups.com
On 9/9/06, Jay Parlar <par...@gmail.com> wrote:

Because 'stockphoto' appears before 'articles' in INSTALLED_APPS,
could it be preventing the ORM from seeing the 'Article' model?

No - like I said before, this block of documentation is just describing the reason that stockphoto needs to be defined in INSTALLED_APPS before articles.

Since Article has a direct dependency on Photo, Photo must be defined first. The relationship between Photo and Article is implied; article_set is (or should be :-) added to Photo when the Article model is loaded.

Yours,
Russ Magee %-)

Jay Parlar

unread,
Sep 9, 2006, 12:29:11 AM9/9/06
to django...@googlegroups.com
On 9/8/06, Russell Keith-Magee <freakb...@gmail.com> wrote:
>
>
>


Alright, that's what I thought.

I'll keep playing with it. This really *feels* like I've just screwed
up something somewhere. I'll update if I find a solution.

Of course, any more suggestions (from anyone) are always welcome :)

Jay P.

Russell Keith-Magee

unread,
Sep 9, 2006, 12:29:45 AM9/9/06
to django...@googlegroups.com
On 9/8/06, Jay Parlar <par...@gmail.com> wrote:

Here's what I tried: Added a Photo and Article from the admin. In the
shell, there was no 'article_set' attribute.

Ok; I tried your models, and I got the same result. I'll look into this a little more and see if I can isolate the exact problem.

Yours,
Russ Magee %-)

Russell Keith-Magee

unread,
Sep 9, 2006, 2:11:34 AM9/9/06
to django...@googlegroups.com
On 9/9/06, Jay Parlar <par...@gmail.com> wrote:

I'll keep playing with it. This really *feels* like I've just screwed
up something somewhere. I'll update if I find a solution.


I've found the problem.

Create an Article and Photo object in the admin view. Then, the following in the shell:

>>> from testproject.mytest.models import Photo
>>> Photo.objects.all()[0].article_set.all()
throws Attribute Error

but, if you then run:

>>> from testproject.mytest2.models import Article
>>> Photo.objects.all()[0].article_set.all()
[<Article: asdf>]

Until you import Article, the related objects for Photo aren't populated.

This is a bit of a 'slaps forehead' moment for me - it's kinda obvious if you know the internals. However, I agree that it isn't obvious for end users. This is worth logging as a bug (if you would be so kind) - both in terms of 'this should be documented more clearly', and 'all related objects should automatically populated'. The first is easy to fix; I'm not so sure about the second.

Yours,
Russ Magee %-)

Jay Parlar

unread,
Sep 9, 2006, 12:18:24 PM9/9/06
to django...@googlegroups.com
On 9/9/06, Russell Keith-Magee <freakb...@gmail.com> wrote:
> I've found the problem.
>
> Create an Article and Photo object in the admin view. Then, the following in
> the shell:
>
> >>> from testproject.mytest.models import Photo
> >>> Photo.objects.all()[0].article_set.all()
> throws Attribute Error
>
> but, if you then run:
>
>
> >>> from testproject.mytest2.models import Article
> >>> Photo.objects.all()[0].article_set.all()
> [<Article: asdf>]
>
> Until you import Article, the related objects for Photo aren't populated.
>
> This is a bit of a 'slaps forehead' moment for me - it's kinda obvious if
> you know the internals. However, I agree that it isn't obvious for end
> users. This is worth logging as a bug (if you would be so kind) - both in
> terms of 'this should be documented more clearly', and 'all related objects
> should automatically populated'. The first is easy to fix; I'm not so sure
> about the second.
>


Sounds good, thanks so much!

Here's something I *just* found though: If instead of:

>>> from testproject.mytest.models import Photo
>>> Photo.objects.all()[0].article_set.all()

you do:

>>> from testproject.mytest.models import Photo
>>> x = Photo.objects.get(id=1).article_set.all()

it all works perfectly! So if you do a get() instead of an all(), the
'article_set' attribute gets created.

I've created a patch (http://code.djangoproject.com/ticket/2684) that
mentions all of this.

Jay P.

Russell Keith-Magee

unread,
Sep 11, 2006, 8:22:04 AM9/11/06
to django...@googlegroups.com
On 9/10/06, Jay Parlar <par...@gmail.com> wrote:
> I've created a patch (http://code.djangoproject.com/ticket/2684) that
> mentions all of this.

The ticket now has a patch to solve the problem. This was a nasty
little edge case; details attached to the patch.

Ordinarily, I would just commit the patch, but there may still be a
development moratorium on django.db.models if effect at the moment
(pending some refactoring from Adrian); I'll try and get confirmation
if this moratorium is still in effect.

Yours
Russ Magee %-)

Jay Parlar

unread,
Sep 11, 2006, 10:02:45 AM9/11/06
to django...@googlegroups.com

Perfect. I'll keep my eye on the ticket. Thanks for all the help on this.

Jay P.

Reply all
Reply to author
Forward
0 new messages