On Thu, 2007-11-01 at 00:43 -0400, George Vilches wrote:
> Karen Tracey wrote:
> > On 10/31/07, *George Vilches* <[EMAIL PROTECTED] 
> > <mailto:[EMAIL PROTECTED]>> wrote:
> > 
> >     Or (I just saw your follow-up e-mail), is all of this a moot point since
> >     something like this is going to be made totally invalid in the future?
> > 
> > 
> > That's it.  Targeting a non-unique column in a ForeignKey field is 
> > invalid.  It's invalid now, and will continue to be invalid.  The 
> > difference is that it's not caught and flagged as an error now, and will 
> > be when queryset-refactor gets merged into trunk. 
> > 
> > If you can whittle down your real problem to an example that does not 
> > include this kind of invalid relationship (you said you are actually 
> > using OneToOne fields?) maybe we could make some progress on 
> > understanding/solving the real issue you are facing.
> 
> Here's an example that's a lot closer to home:
> 
> class Person(models.Model):
>      name = models.CharField(max_length=100)
>      status = models.IntegerField()
> 
> class PersonInfo(models.Model):
>      person = models.OneToOneField(Person)
>      phone = models.CharField(max_length=10)
> 
> 
> 
>  >>> from qs.models import *
>  >>> Person.objects.create(name='user1', status=1)
> <Person: Person object>
>  >>> PersonInfo.objects.create(person_id=1, phone='111')
> <PersonInfo: PersonInfo object>
>  >>> PersonInfo.objects.create(person_id=99, phone='222')
> <PersonInfo: PersonInfo object>
> 
> Yes, I know.  At this point we've added a PersonInfo that doesn't map to 
> an existing person (id=99).
> 
> If at this point you're saying, "well that's stupid", I would ask you to 
> point out where it says that a OneToOneField has any sort of forced 
> referential integrity across the relationship (it most definitely is not 
> generating constraints like the unique ForeignKey does).  

On the contrary, it is asking for referential integrity at database
table creation time. Have a look at the output of "manage.py sql
<appname>" for that app. Unfortunately, SQLite and MySQL with the MyIsam
storage engine won't raise complaints (since they don't enforce the
integrity) and MySQL with the InnoDB engine has what is really a bug in
that you can't use normal SQL syntax to create the Foreign Key, so it
might not be enforcing the constraint either.

You don't mention what database you are using, but if you're using a
backend that doesn't enforce referential integrity, then we can't catch
these types of errors. It's up to you to be careful.

> I don't think 
> it is a requirement,

It is a requirement. It's a one-to-one non-null *relationship*. It must
relate to something!

>  and would ask that you take the rest of this 
> example in that spirit.

Except that examining the results of invalid input is "garbage in,
garbage out". You can't draw conclusions (in fact, you're getting
garbage back because of this bad input; it's not just hypothetical).

>  >>> PersonInfo.objects.count()
> 2L
>  >>> PersonInfo.objects.filter(person__id__gte=-1).count()
> 2L
>  >>> PersonInfo.objects.filter(person__status__gte=-1).count()
> 1L
> 
> So the filter has to be on a non-related field in order to get the query 
> to force the INNER JOIN and not optimize the result out.
> 
> More importantly, I'm getting different counts, and the reasoning seems 
> to be based on an internal optimization. 

The optimisation is entirely valid. What Django does is remove any
comparison to a remote primary key. Since we are comparing to a
non-null, unique field the value on table A's field (the one doing the
referencing) must be the same as the value on table B's primary key
field. No information is lost in removing this join.

There is a subtle bug in this optimisation for to_field attributes. But
that's not what you're seeing and you no doubt came across when
searching for related tickets whilst investigating this (#4088, #4306).

In your example, you've broken referential integrity, which invalidates
one of the invariants of the optimsation. But it's your input data that
is bad. Given invalid input data, all bets are off as to what output you
get.

Please stop trying to twist the ORM beyond all expectations. If you have
relations, they must actually refer to something. Uniquely. You are
poking into edge cases that really don't even look like they should
intuitively, and certainly don't in practice.

Regards,
Malcolm

-- 
Despite the cost of living, have you noticed how popular it remains? 
http://www.pointy-stick.com/blog/


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

Reply via email to