2009-07-16 4 views
3

Ich habeDjango: Warum verwenden Fremdschlüsselabfragen nicht automatisch den PK?

class Achievement(MyBaseModel): 
    pass 

class Alias(MyBaseModel): 
    achievements = models.ManyToManyField('Achievement') 

>>> ach = Achievement.objects.all()[1] 

Dies funktioniert:

>>> Alias.objects.all().filter(achievements__pk__contains=ach.pk).count() 
77L 

Aber dies nicht:

>>> Alias.objects.all().filter(achievements__contains=ach).count() 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/var/home/ptarjan/django/mysite/django/db/models/query.py", line 489, in filter 
    return self._filter_or_exclude(False, *args, **kwargs) 
    File "/var/home/ptarjan/django/mysite/django/db/models/query.py", line 507, in _filter_or_exclude 
    clone.query.add_q(Q(*args, **kwargs)) 
    File "/var/home/ptarjan/django/mysite/django/db/models/sql/query.py", line 1258, in add_q 
    can_reuse=used_aliases) 
    File "/var/home/ptarjan/django/mysite/django/db/models/sql/query.py", line 1201, in add_filter 
    self.where.add((alias, col, field, lookup_type, value), connector) 
    File "/var/home/ptarjan/django/mysite/django/db/models/sql/where.py", line 48, in add 
    params = field.get_db_prep_lookup(lookup_type, value) 
    File "/var/home/ptarjan/django/mysite/django/db/models/fields/related.py", line 156, in get_db_prep_lookup 
    raise TypeError, "Related Field has invalid lookup: %s" % lookup_type 
TypeError: Related Field has invalid lookup: contains 

Warum? (Django 1.0.2)

Mit Blick auf das Abfrageprotokoll tut es etwas, das ich nicht erwartet habe! Diese Abfrage ergab:

>>> connection.queries[-1] 
{'time': '0.027', 'sql': u'SELECT COUNT(*) FROM `yourock_alias` INNER JOIN `yourock_achiever` ON (`yourock_alias`.`id` = `yourock_achiever`.`alias_id`) WHERE `yourock_achiever`.`achievement_id` LIKE BINARY %j0xvw9% '} 

Aber dieses tun

>>> Alias.objects.all().filter(achievements=ach).count() 
77L 

gibt diese Abfrage

>>> connection.queries[-1] 
{'time': '0.023', 'sql': u'SELECT COUNT(*) FROM `yourock_alias` INNER JOIN `yourock_achiever` ON (`yourock_alias`.`id` = `yourock_achiever`.`alias_id`) WHERE `yourock_achiever`.`achievement_id` = j0xvw9 '} 

das ist, was ich wollte, aber die = scheint mir zu verstehen, dass es IS das eine Objekt. Die Abfrage, die django gerade ausführt, wird zurückgegeben, wenn das Objekt irgendwo in der Leistungsliste ist.

Ist das richtig eingerichtet und ist nur sehr kontraintuitiv oder mache ich etwas falsch?

Antwort

1

Im zweiten Fall vergleichen Sie Objekte. Und von Django documentation, um ein Objekt zu vergleichen, müssen Sie den Operator == verwenden.

Darüber hinaus: warum verwenden Sie nicht ach.alias_set.objects.count(), wie in der query section of the manual erklärt?

+0

Ist Ihre Anfrage gleichwertig? Ist es der empfohlene Weg? (Ich bin ein Django-Neuling) –

+0

Ja, ist es. Ich habe einen Link zur Django-Dokumentation hinzugefügt, um zu erfahren, wie man einer Beziehung "rückwärts" folgen kann. –

+0

Ein anderer Grund ist, dass es immer ausschließt, Fremdschlüssel auf mögliche Schlüsselfelder zu setzen (alles, was in der db UNIQUE ist), und das verhindert, dass mehrspaltige Primärschlüssel jemals implementiert werden, was wiederum verhindert, dass Djangos ORM in großen Nicht-Operanden nützlich ist - triviale Schemata. – zxq9

2

Ich kann nicht beantworten, warum die Designentscheidung getroffen wurde, um es auf diese Weise zu implementieren, aber höchstwahrscheinlich folgt es der Python-Philosophie, dass Dinge explizit spezifiziert und nicht impliziert werden sollten.

Der Grund, warum es nicht funktioniert, ist, weil __contains erwartet, dass ein Feld referenziert. Das Bit, an dem Sie es übergeben haben, war eine Referenz auf ein ganzes Objekt.