Frage

Ich war mit einigen Kollegen eine Debatte über diese haben. Gibt es einen bevorzugten Weg, um ein in Django abzuzurufen, wenn Sie erwarten, nur ein?

Die beiden offensichtlichen Möglichkeiten sind:

try:
    obj = MyModel.objects.get(id=1)
except MyModel.DoesNotExist:
    # We have no object! Do something...
    pass

Und:

objs = MyModel.objects.filter(id=1)

if len(objs) == 1:
    obj = objs[0]
else:
    # We have no object! Do something...
    pass

Die erste Methode scheint behaviorally korrektere, verwendet aber Ausnahmen in Steuerströmung, die einigen Aufwand einführen kann. Die zweite ist umständlicher, aber nicht immer eine Ausnahme ausgelöst.

Alle Gedanken auf, welche von diesen wird bevorzugt? Welches ist effizienter?

War es hilfreich?

Lösung

get() ist speziell für diesen Fall vorgesehen. Verwenden Sie es.

Option 2 ist fast genau wie die get() Methode tatsächlich in Django implementiert ist, so sollte es keine „Leistung“ Differenz (und die Tatsache, dass Sie denken über es Sie verletzen eine der Hauptregeln der Programmierung zeigt , nämlich versuchen, Code zu optimieren, bevor es selbst geschrieben worden ist und profiliert - bis Sie den Code haben, und es laufen kann, Sie wissen nicht, wie es durchführen, und bevor dann zu optimieren versuchen, ist ein Weg der Schmerzen)

Andere Tipps

Sie können ein Modul installieren namens django-ärgerlich und dann dies zu tun:

from annoying.functions import get_object_or_None

obj = get_object_or_None(MyModel, id=1)

if not obj:
    #omg the object was not found do some error stuff

1 ist korrekt. In Python hat eine Ausnahme gleich Overhead zu einer Rückkehr. Für einen vereinfachten Nachweis können Sie sich unter diese .

2 Dies ist, was Django im Backend zu tun. get ruft filter und löst eine Ausnahme aus, wenn kein Element gefunden wird, oder wenn mehr als ein Objekt gefunden wird.

Ich bin ein bisschen spät, um die Partei, aber mit Django 1.6 gibt es die first() Methode auf querysets.

https: / /docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.first


  

Gibt das erste durch das queryset angepasst Objekt oder None, wenn kein passendes Objekt ist. Wenn die QuerySet hat keine Reihenfolge definiert ist, dann wird die queryset automatisch vom Primärschlüssel bestellt werden.

Beispiel:

p = Article.objects.order_by('title', 'pub_date').first()
Note that first() is a convenience method, the following code sample is equivalent to the above example:

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None

Ich kann nicht mit Erfahrung von Django aber Option # 1 klar sagt das System sprechen, die Sie für ein Objekt fragen, während die zweite Option nicht. Dies bedeutet, dass Option # 1 könnte leichter Vorteil der Cache oder Datenbankindizes nehmen, insbesondere dann, wenn das Attribut Sie Filterung auf nicht garantiert eindeutig sein.

Auch (wieder spekuliert) die zweite Option, um irgendeine Art von Ergebnissen Sammlung oder Iteratorobjekt seit dem Filter () -Aufruf erstellen kann normalerweise viele Zeilen zurückgeben könnte. Sie würden dies umgehen mit get ().

Schließlich ist die erste Option ist sowohl kürzer und lässt die zusätzliche temporäre Variable - nur ein kleiner Unterschied, aber jedes Bisschen hilft

.

Warum all das? Ersetzen 4 Zeilen mit 1 builtin Verknüpfung. (Dies hat seinen eigenen try / except.)

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, id=1)

Einige weitere Informationen über Ausnahmen. Werden sie nicht erhoben werden, kosten sie fast nichts. Wenn Sie also wissen Sie wahrscheinlich ein Ergebnis haben werden, verwenden Sie die Ausnahme, da ein bedingter Ausdruck verwenden Sie die Kosten für die Überprüfung jedes Mal zahlen, egal was passiert. Auf der anderen Seite sind sie ein bisschen mehr als nur ein bedingter Ausdruck kosten, wenn sie angehoben werden, so dass, wenn Sie erwarten, dass ein Ergebnis mit einem gewissen Frequenz haben (etwa 30% der Zeit, wenn der Speicher dient), schaltet sich die bedingte Check-out um ein bisschen billiger.

Das ist aber Django ORM, und wahrscheinlich auch der Round-Trip in der Datenbank oder sogar einen im Cache gespeicherten Ergebnisses ist wahrscheinlich die Leistungseigenschaften dominieren, so begünstigt Lesbarkeit, in diesem Fall, da Sie erwarten genau ein Ergebnis, Verwendung get() .

Ich habe mit diesem Problem ein wenig gespielt und entdeckt, dass die Option 2 führt zwei SQL-Abfragen, die für eine solche einfache Aufgabe zu groß ist. Siehe meine Anmerkung:

objs = MyModel.objects.filter(id=1) # This does not execute any SQL
if len(objs) == 1: # This executes SELECT COUNT(*) FROM XXX WHERE filter
    obj = objs[0]  # This executes SELECT x, y, z, .. FROM XXX WHERE filter
else: 
    # we have no object!  do something
    pass

Eine äquivalente Version, die eine einzelne Abfrage ausgeführt wird:

items = [item for item in MyModel.objects.filter(id=1)] # executes SELECT x, y, z FROM XXX WHERE filter
count = len(items) # Does not execute any query, items is a standard list.
if count == 0:
   return None
return items[0]

zu diesem Ansatz Durch die Umstellung konnte ich im wesentlichen Anzahl von Anfragen reduzieren meine Anwendung ausgeführt wird.

Interessante Frage, aber für mich Option # 2 stinkt der vorzeitigen Optimierung. Ich bin mir nicht sicher, welche mehr performant, aber Option # 1 sicher aussieht und mehr pythonic mir fühlt.

Ich schlage vor, ein anderes Design.

Wenn Sie eine Funktion auf ein mögliches Ergebnis durchführen möchten, können Sie von QuerySet, wie herleiten: http: //djangosnippets.org/snippets/734/

Das Ergebnis ist ziemlich genial, man könnte zum Beispiel:

MyModel.objects.filter(id=1).yourFunction()

Hier Filter gibt entweder einen leeren queryset oder eine queryset mit einem einzigen Element. Ihre individuelle queryset Funktionen sind auch verkettbar und wiederverwendbar. Wenn Sie möchten, um es auszuführen für alle Eingaben. MyModel.objects.all().yourFunction()

Sie sind auch ideal als Aktionen im Admin-Interface verwendet werden:

def yourAction(self, request, queryset):
    queryset.yourFunction()

Option 1 ist eleganter, aber sicher sein try..except zu verwenden.

Aus meiner eigenen Erfahrung kann ich Ihnen sagen, dass manchmal sind Sie sicher, kann es möglicherweise nicht mehr sein als ein passendes Objekt in der Datenbank, und doch wird es zwei sein ... (außer natürlich, wenn das Objekt von seiner primären bekommen Taste).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top