Django : DB에서 객체를 얻거나 일치하는 것이 없으면 'None'


101

데이터베이스에서 객체를 얻을 수있는 Django 함수가 있습니까? 아니면 아무것도 일치하지 않으면 None?

지금은 다음과 같은 것을 사용하고 있습니다.

foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None

그러나 그것은 그다지 명확하지 않으며 모든 곳에있는 것이 지저분합니다.


2
당신은 그냥 foo에 사용할 수 있습니다 알고 = foo는 [0]의 경우 foo는 다른 없음
Visgean Skeloru

2
Python에는 삼항 연산자가 있으므로 부울 연산자를 사용할 필요가 없습니다. 또한 len(foo)나쁜 점은 다음과 같습니다. " 참고 : 집합의 레코드 수를 확인하는 것뿐이라면 QuerySets에서 len ()을 사용하지 마십시오. SQL의 SELECT COUNT를 사용하여 데이터베이스 수준에서 개수를 처리하는 것이 훨씬 더 효율적입니다. (), Django는 정확히 이러한 이유로 count () 메소드를 제공합니다. ". 재 작성 :foo = foo[0] if foo.exists() else None
mustafa.0x 2013 년


1
@ mustafa.0x 여기에 적용되지 않는다고 생각합니다. 여기서 카운트를 확인하면 다른 쿼리가 실행됩니다. 그런 다음 실제 데이터를 얻기 위해 다시 쿼리해야합니다. 이것은 필터링하고 계산하는 것이 더 의미가있는 경우입니다 ... 그러나 필터링하고 호출하는 것보다 더 의미가 없습니다 first(). : P
MicronXD

답변:


88

Django 1.6 에서는 다음을 사용할 수 있습니다.first() Queryset 메서드를 . 쿼리 셋과 일치하는 첫 번째 개체를 반환하거나 일치하는 개체가 없으면 None을 반환합니다.

용법:

p = Article.objects.order_by('title', 'pub_date').first()

19
이것은 좋은 대답이 아닙니다. 여러 객체가 발견되면 여기에MultipleObjectsReturned() 설명 된대로 발생하지 않습니다 . 당신은 더 좋은 답을 찾을 수 있습니다 여기에
sleepycal

25
@sleepycal 동의하지 않습니다. first()작품은 정확하게는에 가정한다. 쿼리 결과에서 첫 번째 개체를 반환하고 여러 결과가 발견 되더라도 상관하지 않습니다. 반환 된 여러 개체를 확인해야하는 경우 .get()대신 사용해야 합니다.
Cesar Canassa

7
OP가 말했듯이, .get()그의 필요에 적합하지 않습니다. 이 질문에 대한 정답은 @kaapstorm에서 찾을 수 있으며 분명히 더 적합한 대답입니다. filter()이런 식으로 남용 하면 예상치 못한 결과가 발생할 수 있습니다. OP는 아마 깨닫지 못한 결과를 초래할 수 있습니다 (여기에 뭔가
빠뜨리지

1
@sleepycal이 접근 방식에서 어떤 의도하지 않은 결과가 발생합니까?
HorseloverFat

12
데이터베이스 제약 조건이 개체 간의 고유성을 올바르게 관리하지 못하는 경우 논리가 단일 개체 (first ()에 의해 선택됨) 만있을 것으로 예상하지만 실제로는 여러 개체가 존재하는 경우가 발생할 수 있습니다. first () 대신 get ()을 사용하면 MultipleObjectsReturned(). 반환되는 결과가 여러 개체를 반환 할 것으로 예상되지 않는 경우에는 그렇게 처리해서는 안됩니다. 여기에 대해 논쟁이 있었습니다
sleepycal

139

이를 수행하는 두 가지 방법이 있습니다.

try:
    foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
    foo = None

또는 래퍼를 사용할 수 있습니다.

def get_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

이렇게 불러

foo = get_or_none(Foo, baz=bar)

8
기능에 예외를 사용하고 있다는 사실이 마음에 들지 않습니다. 이것은 대부분의 언어에서 나쁜 습관입니다. 파이썬에서는 어떻습니까?
pcv

18
이것이 Python 반복이 작동하는 방식 (StopIteration 발생)이며, 언어의 핵심 부분입니다. 나는 try / except 기능의 열렬한 팬은 아니지만 Pythonic으로 간주되는 것 같습니다.
Matt Luongo

4
@pcv : "대부분의"언어에 대한 신뢰할 수있는 통념이 없습니다. 나는 당신이 우연히 사용하는 특정 언어에 대해 생각한다고 가정하지만 그러한 수량자를 조심하십시오. 예외는 파이썬의 모든 것만 큼 느릴 수 있습니다 (또는 그 문제에 대해 "충분히 빠름"). 다시 질문으로 돌아가서 queryset1.6 이전에이 작업을 수행 하는 방법을 제공하지 않은 것은 프레임 워크의 단점입니다 ! 그러나이 구조는 서투른 것입니다. 좋아하는 언어의 일부 튜토리얼 작성자가 그렇게 말했기 때문에 "악"이 아닙니다. Google을 사용해보십시오 : "허가보다는 용서를 구하십시오".
토마스 Gandor

@TomaszGandor : 네, 좋아하는 언어 튜토리얼이 뭐라고하든 서투르고 읽기가 어렵습니다. 예외가 발생하면 비표준이 발생한다고 가정합니다. 가독성이 중요합니다. 그러나 다른 합리적인 선택이 없을 때 동의합니다. 당신은 그것을 선택해야하며 나쁜 일은 없을 것입니다.
pcv

@pcv get메소드는을 반환하지 않기 None때문에 예외가 의미가 있습니다. 개체가 거기에있을 것이라고 확신하거나 개체가 거기에있을 것이라고 "추정"하는 경우에 사용해야합니다. 또한 이와 같은 예외를 사용하는 것은 '괜찮은'것으로 간주됩니다. 당신은 원하는 get당신이 예외를 catch하고 이후에있어 변화 인을 억제하므로, 다른 계약.
Dan Passaro

83

sorki의 답변에 몇 가지 샘플 코드를 추가하기 위해 (나는 이것을 댓글로 추가하고 싶지만 이것은 내 첫 번째 게시물이며 댓글을 남길만한 평판이 충분하지 않습니다) 다음과 같이 get_or_none 사용자 지정 관리자를 구현했습니다.

from django.db import models

class GetOrNoneManager(models.Manager):
    """Adds get_or_none method to objects
    """
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None

class Person(models.Model):
    name = models.CharField(max_length=255)
    objects = GetOrNoneManager()

이제 이렇게 할 수 있습니다.

bob_or_none = Person.objects.get_or_none(name='Bob')

이것은 매우 우아합니다.
NotSimon 2014-04-11

13

django를 귀찮게 사용해 볼 수도 있습니다 (다른 유용한 기능이 있습니다!).

다음과 함께 설치하십시오.

pip install django-annoying

from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)

9

Foo 에게 맞춤 관리자를 제공합니다 . 매우 쉽습니다. 사용자 지정 관리자의 함수에 코드를 넣고 모델에 사용자 지정 관리자를 설정 한 다음Foo.objects.your_new_func(...) .

일반 함수가 필요한 경우 (사용자 지정 관리자가 아닌 모든 모델에서 사용) 직접 작성하고 Python 경로에 배치하고 더 이상 지저분하지 않게 가져옵니다.


4

관리자 또는 일반 함수를 통해 수행하든, kwargs가 둘 이상의 객체를 검색하면 get () 함수가이를 발생시키기 때문에 TRY 문에서 'MultipleObjectsReturned'를 포착 할 수도 있습니다.

일반 기능을 기반으로 구축 :

def get_unique_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except (model.DoesNotExist, model.MultipleObjectsReturned), err:
        return None

그리고 매니저에서 :

class GetUniqueOrNoneManager(models.Manager):
    """Adds get_unique_or_none method to objects
    """
    def get_unique_or_none(self, *args, **kwargs):
        try:
            return self.get(*args, **kwargs)
        except (self.model.DoesNotExist, self.model.MultipleObjectsReturned), err:
            return None

이것은 다른 답변의 모든 장점을 포착하는 것 같습니다. 좋은 일 :)
에드워드 뉴웰

@emispowder, None을 반환하지 않으려면 SAME 페이지에 "일치하는 데이터 없음"과 같은 경고 메시지를 반환하고 싶습니다.
Héléna 2015

0

다음 QuerySet은 모델의 all객체 쿼리 셋이 아닌 쿼리 셋 (예 : 상위 인스턴스) :

def get_unique_or_none(model, queryset=None, *args, **kwargs):
    """
        Performs the query on the specified `queryset`
        (defaulting to the `all` queryset of the `model`'s default manager)
        and returns the unique object matching the given
        keyword arguments.  Returns `None` if no match is found.
        Throws a `model.MultipleObjectsReturned` exception
        if more than one match is found.
    """
    if queryset is None:
        queryset = model.objects.all()
    try:
        return queryset.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

두 가지 방법으로 사용할 수 있습니다. 예 :

  1. obj = get_unique_or_none(Model, *args, **kwargs) 앞서 논의했듯이
  2. obj = get_unique_or_none(Model, parent.children, *args, **kwargs)

-1

대부분의 경우 다음을 사용할 수 있다고 생각합니다.

foo, created = Foo.objects.get_or_create(bar=baz)

Foo 테이블에 새 항목이 추가되는 것이 중요하지 않은 경우에만 (다른 열에는 없음 / 기본값이 있음)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.