On Fri, Feb 12, 2010 at 3:47 PM, Luc Saffre <luc.saf...@gmx.net> wrote:
> Sorry, but the longer we discuss, the more it becomes clear: Django's
> behaviour is certainly wrong.

No, it really isn't *certainly* wrong. It's *arguably* wrong, and I
join my colleagues Luke and Karen in arguing that it isn't wrong at
all.

> I'm puzzled how no Django core developer seems to understand it. I hope
> that this is just because they are not following this thread because
> there is admittedly more urgent work to do right now.
>
> With the danger of repeating myself I explain once more:
>
> Example models:
>
>  class Owner(models.Model):
>      pass
>
>  class Animal(models.Model):  # nullable owner
>      owner = models.ForeignKey(Owner,blank=True,null=True)
>
>  class Thing(models.Model):   # non-nullable owner
>      owner = models.ForeignKey(Owner)
>
> There should never be a related lookup when the fk_id is None. For
> nullable FK Django behaves correctly:
>
>  >>> a = Animal()
>  >>> print a.owner
>  None

Yes. The owner hasn't been specified. Therefore, the field falls back
to it's default value -- the owner is None.

> The same doesn't work for non-nullable FK:
>
>  >>> t = Thing()
>  >>> print t.owner
>  Traceback (most recent call last):
>  ...
>  DoesNotExist

Yes. The owner hasn't been specified. The owner *must* be specified,
so any attempt to access it is an error - the owner Does Not Exist.

> This is whay I say that Django treats non-nullable FK in a special way.

Yes. Personally, I see the nullable case as the special case, but it
doesn't really matter which way you look at it -- the two behave
differently because they *are* different.

> It is as if Django thinks "Since Thing.owner may not be None, I can do
> the lookup without even testing for a None value".

Exactly. There's no point looking for a None value, because the field
*can't have a value of None*.

> The correct exception is risen when you try to save it:
>
>  >>> t.save()
>  Traceback (most recent call last):
>  ...
>  IntegrityError: 20100212_thing.owner_id may not be NULL
>
> How can you not understand that the DoesNotExist exception above is
> risen too early? It is a bug!

How can you *not* understand that this is a difference of opinion?
Three Django core developers (Luke, Karen and myself) have
independently told you that they disagree that this is "certainly
wrong".

In one last attempt to explain why Django works the way it does: it
may help to think of the problem in these terms. Thing.owner *isn't* a
field on Thing. It may be defined there, but what it is defining is a
relationship with the Owner table. Thing.owner is a descriptor that
substitutes for a query on the "Owner" table.

When you ask for Thing.owner, you're really saying "Give me the Owner
with a relationship to Thing X". If Thing X hasn't defined a
relationship with an owner, then the Owner.DoesNotExist.

In the case of the Animal, a legitimate answer to the question "Give
me the owner with a relationship to Animal X' is "no owner" - hence,
None is a legal return value.

Hopefully that clarifies why Django works the way it does. However,
even if, hypothetically, we were to accept that Django's current
behavior is in error, and your interpretation is the only correct
interpretation, there is an enormous issue of practicality. This
behavior was introduced as part of the 'magic-removal' branch, which
is 4 years old. The current behavior closely mirrors the analogous
behavior that preceded it. The current behavior has been a formal,
documented part of the 0.96, 0.96, 1.0, and 1.1 releases. There are
quite literally *thousands* of projects in production that rely on
Django's behavior being predictable and consistent between versions -
even if that behavior isn't "correct".

Changing this behavior would be a *huge* undertaking. If we were
talking about some esoteric corner of the aggregation API, we might be
able to entertain making a backwards-incompatible change -- but you're
talking about changing a fundamental aspect of the way foreign keys
work, and have always worked, and have been documented to work.

Django has been used by many people, over a long period of time. The
criticism of the API you are raising is *not* a regular feature of
complaints on Django-users, so there is very little reason to believe
that it is causing significant practical difficulties. Although the
change would be a minor code modification, it would be *very*
complicated to change it in practice, given Django's API backwards
compatibility guarantee. And as a result, we're *not* going to change
it.

Yours,
Russ Magee %-)

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to