문제

나는 일부 동료들과 이것에 대해 토론하고있었습니다. 객체만을 기대할 때 객체를 검색하는 선호하는 방법이 있습니까?

두 가지 명백한 방법은 다음과 같습니다.

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

그리고:

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

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

첫 번째 방법은 행동 적으로 더 정확해 보이지만 제어 흐름에 예외를 사용하여 일부 오버 헤드가 발생할 수 있습니다. 두 번째는 더 원형 교차로이지만 예외를 제기하지는 않습니다.

이 중 어느 것에 대한 생각이 바람직합니까? 어느 것이 더 효율적입니까?

도움이 되었습니까?

해결책

get() 이 경우에 특별히 제공됩니다. 그걸 써.

옵션 2는 거의 정확하게 get() 메소드는 실제로 Django에서 구현되므로 "성능"차이가 없어야합니다. 프로파일 링 - 코드를 가지고 실행할 수있을 때까지, 그것이 어떻게 수행 될지 알지 못하고 그 전에 최적화하려고하는 것은 고통의 길입니다).

다른 팁

호출 된 모듈을 설치할 수 있습니다 장고 아노 잉 그런 다음이 작업을 수행합니다.

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이 정확합니다. 파이썬에서 예외는 반품과 동일한 오버 헤드를 갖습니다. 단순화 된 증거를 위해서는 볼 수 있습니다 이것.

2 이것이 Django가 백엔드에서하는 일입니다. get 전화 filter 항목이 없거나 하나 이상의 객체가 발견되면 예외가 발생합니다.

나는 파티에 조금 늦었지만 Django 1.6과 함께 first() 쿼리 세트의 메소드.

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


쿼리 세트와 일치하는 첫 번째 객체를 반환하거나 일치하는 객체가없는 경우 없음. 쿼리 세트에 주문 정의가없는 경우 기본 키에 의해 쿼리 세트가 자동으로 주문됩니다.

예시:

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

Django의 경험에 대해서는 말할 수 없지만 옵션 #1은 시스템에 1 개 객체를 요구하는 시스템에 명확하게 말하지만 두 번째 옵션은 그렇지 않습니다. 즉, 옵션 #1은 캐시 또는 데이터베이스 인덱스를 더 쉽게 활용할 수 있습니다. 특히 필터링 속성이 고유한지 보장되지 않는 경우.

또한 필터 () 호출이 일반적으로 많은 행을 반환 할 수 있으므로 두 번째 옵션은 일종의 결과 수집 또는 반복자 객체를 만들어야 할 수도 있습니다. 당신은 이것을 get ()로 우회합니다.

마지막으로, 첫 번째 옵션은 짧고 추가 임시 변수를 생략합니다. 사소한 차이 만 있지만 모든 작은 도움이됩니다.

왜 그 모든 것이 작동합니까? 1 개의 내장 단축키로 4 줄을 교체하십시오. (이것은 자체 시도/제외합니다.)

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, id=1)

예외에 대한 더 많은 정보. 그들이 자라지 않으면 거의 비용이 들지 않습니다. 따라서 당신이 결과를 얻을 수 있다는 것을 알고 있다면, 조건부 표현식을 사용하여 매번 점검 비용을 지불하기 때문에 예외를 사용하십시오. 다른 한편으로, 그들은 제기 될 때 조건부 표현보다 약간 더 많은 비용이 들기 때문에, 약간의 빈도 (예 : 30%의 시간, 메모리가 제공되는 경우)로 결과가 없을 것으로 예상하면 조건부 점검이 밝혀졌습니다. 조금 저렴합니다.

그러나 이것은 Django의 ORM이며, 아마도 데이터베이스에 대한 왕복 또는 캐시 된 결과는 성능 특성을 지배 할 가능성이 높으므로, 정확히 하나의 결과를 기대하기 때문에 유리한 가독성이 있습니다. get().

나는이 문제를 다소 연주했고 옵션 2가 두 개의 SQL 쿼리를 실행한다는 것을 발견했습니다. 내 주석보기 :

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

단일 쿼리를 실행하는 동등한 버전은 다음과 같습니다.

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]

이 접근법으로 전환함으로써 응용 프로그램이 실행하는 쿼리 수를 실질적으로 줄일 수있었습니다.

흥미로운 질문이지만 저에게 옵션 #2 조기 최적화의 reeks. 나는 어느 것이 더 성능이 있는지 잘 모르겠지만, 옵션 #1은 확실히 나에게 더 많은 피스닉을 느끼고 느낍니다.

다른 디자인을 제안합니다.

가능한 결과에서 함수를 수행하려면 다음과 같이 QuerySet에서 파생 할 수 있습니다. http://djangosnippets.org/snippets/734/

결과는 정말 대단합니다. 예를 들어 다음과 같이 할 수 있습니다.

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

여기서 필터는 빈 쿼리 세트 또는 단일 항목으로 쿼리 세트를 반환합니다. 사용자 정의 쿼리 세트 기능도 체인 가능하고 재사용 가능합니다. 모든 항목에 대해 수행하려는 경우 : MyModel.objects.all().yourFunction().

또한 관리자 인터페이스에서 동작으로 사용하기에 이상적입니다.

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

옵션 1은 더 우아하지만 시도해보십시오.

내 자신의 경험에서 나는 때때로 당신이 데이터베이스에 둘 이상의 일치하는 객체가있을 수 없다고 확신 할 수 있지만, 두 개가있을 것입니다 ...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top