Подтвердить что ты не робот

Django: получить первый объект из запроса фильтра или создать

В Django queryset предоставляет метод get_or_create, который возвращает объекты или создает объект.

Однако, как и метод get, get_or_create может генерировать исключение, если запрос возвращает несколько объектов.

Есть ли способ сделать это элегантно:

objects = Model.manager.filter(params)
if len(objects) == 0:
   obj = Model.objects.create(params)
else:
   obj = objects[0]
4b9b3361

Ответ 1

get_or_create() - это просто удобная функция, поэтому нет ничего плохого в написании собственного, как показано в павиде, или

result = Model.objects.filter(field__lookup=value)[0]
if not result:
   result = Model.objects.create(...)
return result

ИЗМЕНИТЬ Как было предложено, сменил срез [: 1] (который возвращает список с одним входом) после фильтра на [0] (который возвращает фактический объект). Проблема с этим - это вызовет исключение, если оно не соответствует запросу.

Это также приведет к исключению simliar:

Model.objects.filter(field_lookup=value).latest()

Глядя на вопрос снова, я не уверен, хочет ли исходный плакат возвращать несколько объектов/строк или просто способ обхода исключения при извлечении одного объекта/строки.

Вот еще один вариант?

results = Model.objects.filter(...)
if results.exists():
    return results
else:
    return Model.objects.create(...)

а другой:

result = None
try:
    result = Model.objects.get(...)
except Model.DoesNotExist:
    result = Model.objects.create(...)

Нет ничего плохого в том, чтобы поднимать и ловить исключения!

Ответ 2

Из django 1.6 существует метод удобства first(), который возвращает первый результат в запросе фильтра или None.

obj = Model.manager.filter(params).first()
if obj is None:
    obj = Model.objects.create(params)

Ответ 3

Я только наткнулся на этот вопрос и хотел внести свой вклад, потому что никто не предложил на самом деле поймать IndexError.

try:
    obj = Model.objects.filter(params)[0]
except IndexError:
    obj = Model.objects.create(params)

Ответ 4

Здесь используется метод диспетчера, который позволит вам элегантно расширить эту функцию

class FilterOrCreateManager(models.Manager):
"""Adds filter_or_create method to objects
"""
def filter_or_create(self, **kwargs):
  try:
    created = False
    obj = self.filter(**kwargs).first()
    if obj is None:
      obj = self.create(**kwargs)
      created = True
    return (obj,created)
  except Exception as e:        
    print(e)

Затем убедитесь, что вы добавили менеджера в зависимости от того, какую модель вы хотите использовать:

class MyObj(models.Model):
  objects = FilterOrCreateManager()

После этого вы сможете использовать его, как вы бы get_or_create:

obj_instance, created = MyObj.filter_or_create(somearg='some value')

Ответ 5

Вы можете попробовать следующее:

result = Model.objects.filter(field__lookup=value)[0]
if not result:
   result = Model.objects.create(...)
return result

Ответ 6

Это работает для меня:

На ваш взгляд, вызовите что-то вроде этого:

obj = Category.objects.get_or_create_category(form.cleaned_data.get('name'))

В диспетчере моделей создайте такую ​​функцию:

class CategoryManager(models.Manager):

    def get_or_create_category(self, query):
        try:
            result = Category.objects.filter(name = query)[0]
        except:
            result = Category.objects.create(name = query)
        return result

Логика проста. Сначала попробуйте получить первый объект категории, имя которого соответствует строке запроса (которая предоставляется формой). Если сбой поиска (поскольку он не существует), создайте новую категорию со строкой в ​​качестве ее имени. Верните результат для использования в вашем представлении.

Ответ 7

Если я правильно понял, вы хотите получить предмет, или если он не существует, создать.

Итак, вы можете попробовать с ошибкой исключения, но я не уверен, какой из них наиболее эффективен:

try:
    Model.objects.filter(params)[0]
except Model.IndexError:
    Model.objects.create(params)