Создайте модель Django или обновите, если существует

116

Я хочу создать объект модели, например Person, если идентификатор человека не существует, или я получу этот объект человека.

Код для создания нового человека выглядит следующим образом:

class Person(models.Model):
    identifier = models.CharField(max_length = 10)
    name = models.CharField(max_length = 20)
    objects = PersonManager()

class PersonManager(models.Manager):
    def create_person(self, identifier):
        person = self.create(identifier = identifier)
        return person

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

user1687717
источник

Ответы:

169

Если вы ищете вариант использования "обновить, если существует еще, создать", см. Отличный ответ @Zags


Джанго уже есть get_or_create, https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

Для вас это могло быть:

id = 'some identifier'
person, created = Person.objects.get_or_create(identifier=id)

if created:
   # means you have created a new person
else:
   # person just refers to the existing one
Bakkal
источник
Я использую django 1.9, и он дает мне: AttributeError: объект 'QuerySet' не имеет атрибута 'update_or_create'
Офек Гила,
1
@OfekGila Это странно, как исходный код и документация подтверждение QuerySetимеетupdate_or_create
Bakkal
2
В моем случае вместо идентификатора у меня есть группа полей, которая формирует unique_to together. Как использование в этом случае?
Rakmo
192

Неясно, запрашивает ли ваш вопрос метод get_or_create (доступный как минимум в Django 1.3) или метод update_or_create (новый в Django 1.7). Это зависит от того, как вы хотите обновить объект пользователя.

Пример использования следующий:

# In both cases, the call will get a person object with matching
# identifier or create one if none exists; if a person is created,
# it will be created with name equal to the value in `name`.

# In this case, if the Person already exists, its existing name is preserved
person, created = Person.objects.get_or_create(
        identifier=identifier, defaults={"name": name}
)

# In this case, if the Person already exists, its name is updated
person, created = Person.objects.update_or_create(
        identifier=identifier, defaults={"name": name}
)
Загс
источник
12
+1, update_or_createпотому что для этого варианта использования лучше, чем get_or_createпросто снова вызвать save()объект.
bakkal
В моем случае вместо идентификатора у меня есть группа полей, которая формирует unique_to together. Как использование в этом случае?
Rakmo
1
Идентификатор @OmkarDeshpande - это просто пример; вы можете передать любой действительный запрос django, напримерPerson.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags
Что, если я хочу добавить к созданному человеку больше полей, чем по умолчанию?
Ло Беллин
@LoBellin defaultsаргумент этих функций - это то место, где вы указываете, какие поля вы хотите добавить в модель. Это не имеет ничего общего со значениями по умолчанию, указанными в полях вашей модели
Zags
10

Django поддерживает это, проверьте get_or_create

person, created = Person.objects.get_or_create(name='abc')
if created:
    # A new person object created
else:
    # person object already exists
Аамир Аднан
источник
4

Только для небольшого количества объектов update_or_create работает хорошо, но если вы работаете с большой коллекцией, он не будет хорошо масштабироваться. update_or_create всегда сначала запускает SELECT, а затем UPDATE.

for the_bar in bars:
    updated_rows = SomeModel.objects.filter(bar=the_bar).update(foo=100)
        if not updated_rows:
            # if not exists, create new
            SomeModel.objects.create(bar=the_bar, foo=100)

В лучшем случае это будет запускать только первый запрос обновления, и только если он соответствует нулевым строкам, запускает другой запрос INSERT. Это значительно увеличит вашу производительность, если вы ожидаете, что большинство строк действительно существует.

Однако все сводится к вашему варианту использования. Если вы ожидаете в основном вставок, то, возможно, в качестве варианта может быть использована команда bulk_create () .

Андреас Бергстрём
источник
3

Подумал, что добавлю ответ, так как заголовок вашего вопроса выглядит так, будто спрашивает, как создать или обновить, а не получить или создать, как описано в теле вопроса.

Если вы действительно хотите создать или обновить объект, метод .save () уже имеет это поведение по умолчанию, из документации :

Django абстрагирует необходимость использования операторов SQL INSERT или UPDATE. В частности, когда вы вызываете save (), Django следует этому алгоритму:

Если для атрибута первичного ключа объекта установлено значение, которое оценивается как True (то есть значение, отличное от None или пустой строки), Django выполняет UPDATE. Если атрибут первичного ключа объекта не установлен или UPDATE ничего не обновил, Django выполняет INSERT.

Стоит отметить, что когда они говорят «если ОБНОВЛЕНИЕ ничего не обновляло», они по существу имеют в виду случай, когда идентификатор, который вы дали объекту, еще не существует в базе данных.

Том Мантерфилд
источник
1

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

Person.objects.get_or_create(id=1)

Он будет автоматически обновляться, если существует, поскольку два данных с одним и тем же первичным ключом не допускаются.

Амина Нураини
источник