2016-08-17 2 views
-2

Много раз я нахожу себя фильтрацией для объекта и возвращаю None, если его не найти. Однако этот метод я делаю это, кажется, действительно неэффективно (в терминах строк кода)Лучший способ фильтрации в Django и увидеть, существует ли объект

Когда я фильтр для объекта я обычно делаю что-то вроде этого:

person = Person.objects.filter(id=id) 
if person: 
    person = Person.objects.get(id=id) 
else: 
    person = None 

Есть ли лучший способ сделать это ?

Редактировать Я внес изменения для разъяснения путаницы на моем конце. Запрос фильтра всегда должен возвращать 1 объект, если он существует.

+0

'если не person'? – roganjosh

+1

Или, может быть, коалесцирующий оператор 'person = Person.objects.filter (name = name) или None'? Это должно быть по умолчанию 'person = None', если' Person.objects.filter (name = name) 'falsy – roganjosh

+0

Я не понимаю, почему вы повторяете фильтр в инструкции if. –

ответ

1

Просто используйте .get(), если вы хотите получить одного человека или вернуть None.

try: 
    person = Person.objects.get(name=name) 
except (Person.DoesNotExist, Person.MultipleObjectsReturned) as e: 
    person = None 
+0

это действительно плохая идея, потому что Exception будет поднят, даже если это будет какая-то проблема с db (соединение и т. Д.). И человек может легко быть там, но вы возвращаете Ничего. –

+0

Понятно, я исправлю это. –

+0

Есть ли однострочное решение для этого? Он видит, что это немного код для чего-то общего запроса. –

1

Ваш if/else необычен тем, что вы назначаете person дважды. Я не понимаю, почему. У меня есть два варианта.

Во-первых, вы можете уменьшить if/else к только if вроде этого:

person = Person.objects.filter(name=name) 
if not person: 
    person = None 

Или с coalescing operator сделать это очень лаконична:

person = Person.objects.filter(name=name) or None 

который будет возвращать person = None если Person.objects.filter(name=name) является falsy.

+0

Это было бы здорово, если бы я мог использовать '.get', и запрос не разбился, когда ожидается, что None будет возвращен. –

+0

@JohnSmith редактирование на ваш вопрос сделало его совершенно другим. Изначально вы повторяли 'filter' в' if/else', поэтому мой 1-лайнер точно такой же, как и то, что вы делали изначально. Теперь это не имеет смысла. – roganjosh

1

список обратного фильтра (или пустой список), так что если вы знаете, вы получите список, и хотите, чтобы заменить пустой список с None:

persons = Person.objects.filter(name=name) 
if not any(person): 
    person = None 
# single person 
person = persons[0] # but there could be more than one 

Если вы хотите один человек

try: 
    person = Person.objects.get(name=name) 
except Person.MultipleObjectsReturned: 
    # do something if there is more Persons with that name 
    person = Person.objects.first() # for example return first person with that name 
except Person.DoesNotExist: 
    person = None # set person None 
+0

Зачем вам нужно 'any()' здесь? Это пустой список, который является ложным. 'если не человек'? – roganjosh

+0

Если он не пуст, он будет истребителем полного списка ->, поэтому он будет медленнее, если есть более одного человека, ** любая функция ** возвращает true, если есть человек [0] или False, если он не является человеком [0 ] –

+0

Я не уверен, что понимаю. '[]' всегда будет возвращать false, и ничто не должно повторяться, потому что список просто пуст. Список с элементами в нем вернет «Истинный», но не обязательно ли перебирать весь список для проверки? – roganjosh

1

Вы можете использовать exists()

Из docs:

Если вы хотите, чтобы определить, по меньшей мере, один результат существует (и не нужны реальные объекты), это больше эффективное использование существует().

entry = Entry.objects.get(pk=123) 
if some_queryset.filter(pk=entry.pk).exists(): 
    print("Entry contained in queryset") 
else: 
    return None 

Вы можете сократить это немного, если строки кода вызывает беспокойство. Однако:

Кроме того, если some_queryset еще не был оценен, но вы знаете, что это будет в какой-то момент, то с помощью some_queryset.exists() будет делать больше общей работы (один запрос для существования проверьте плюс дополнительный номер , чтобы получить результаты), чем просто используя bool (some_queryset), который извлекает результаты, а затем проверяет, были ли возвращены .

+0

Я собираюсь под заголовком вашего вопроса с этим ответом - как узнать, существует ли объект *. –

1

Вы не можете сделать это.

person = Person.objects.get(name=name) 

вызовет исключение.

Что вы можете сделать, это:

try: 
    person = Person.objects.get(name=name) 
except Person.MultipleObjectsReturned: 
    person = Person.objects.first() 
except Person.DoesNotExist: 
    person = None 

Но Лучше всего здесь использовать:

some_queryset.filter(pk=entry.pk).exists() 
Смежные вопросы