Buat model Django atau perbarui jika ada

115

Saya ingin membuat objek model, seperti Person, jika id person tidak ada, atau saya akan mendapatkan objek person tersebut.

Kode untuk membuat orang baru sebagai berikut:

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

Tapi saya tidak tahu di mana harus memeriksa dan mendapatkan objek person yang ada.

pengguna1687717
sumber

Jawaban:

169

Jika Anda mencari kasus penggunaan "perbarui jika ada, buat", lihat jawaban yang sangat baik di @Zags


Django sudah memiliki get_or_create, https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

Untuk Anda ini bisa jadi:

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
sumber
Saya menggunakan django 1.9, dan ini memberi saya: AttributeError: objek 'QuerySet' tidak memiliki atribut 'update_or_create'
Ofek Gila
1
@OfekGila Itu aneh, baik kode sumber maupun dokumentasinyaQuerySet telah dikonfirmasiupdate_or_create
bakkal
2
Dalam kasus saya, sebagai ganti pengenal, saya memiliki grup bidang yang membentuk unique_together. Bagaimana penggunaan kasus ini?
Rakmo
191

Tidak jelas apakah pertanyaan Anda menanyakan metode get_or_create (tersedia setidaknya dari Django 1.3) atau metode update_or_create (baru di Django 1.7). Itu tergantung pada bagaimana Anda ingin memperbarui objek pengguna.

Contoh penggunaan adalah sebagai berikut:

# 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}
)
Zags
sumber
12
1 untuk update_or_createkarena untuk kasus penggunaan itu lebih baik daripada get_or_createhanya memanggil save()objek itu lagi.
bakkal
Dalam kasus saya, sebagai ganti pengenal, saya memiliki grup bidang yang membentuk unique_together. Bagaimana penggunaan kasus ini?
Rakmo
1
Pengenal @OmkarDeshpande hanyalah sebuah contoh; Anda bisa meneruskan kueri django yang valid, sepertiPerson.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags
Bagaimana jika saya ingin menambahkan lebih banyak bidang ke Orang yang dibuat daripada yang default?
Lo Bellin
@LoBellin defaultsargumen untuk fungsi ini adalah tempat Anda menentukan bidang apa yang ingin Anda tambahkan ke model. Ini tidak ada hubungannya dengan default yang ditentukan pada bidang model Anda
Zags
10

Django memiliki dukungan untuk ini, periksa get_or_create

person, created = Person.objects.get_or_create(name='abc')
if created:
    # A new person object created
else:
    # person object already exists
Aamir Adnan
sumber
4

Untuk objek dalam jumlah kecil, update_or_create berfungsi dengan baik, tetapi jika Anda melakukan terlalu banyak koleksi, itu tidak akan diskalakan dengan baik. update_or_create selalu pertama menjalankan SELECT dan setelah itu 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)

Ini paling baik hanya akan menjalankan kueri pembaruan pertama, dan hanya jika cocok dengan baris nol menjalankan kueri INSERT lain. Yang akan sangat meningkatkan kinerja Anda jika Anda mengharapkan sebagian besar baris benar-benar ada.

Itu semua tergantung pada kasus penggunaan Anda. Jika Anda mengharapkan sebagian besar sisipan maka mungkin perintah bulk_create () bisa menjadi opsi.

Andreas Bergström
sumber
3

Saya pikir saya akan menambahkan jawaban karena judul pertanyaan Anda sepertinya menanyakan cara membuat atau memperbarui, daripada mendapatkan atau membuat seperti yang dijelaskan dalam badan pertanyaan.

Jika Anda memang ingin membuat atau memperbarui objek, metode .save () sudah memiliki perilaku ini secara default, dari dokumen :

Django mengabstraksikan kebutuhan untuk menggunakan pernyataan INSERT atau UPDATE SQL. Secara khusus, ketika Anda memanggil save (), Django mengikuti algoritma ini:

Jika atribut kunci utama objek diset ke nilai yang mengevaluasi ke True (yaitu, nilai selain dari Nihil atau string kosong), Django menjalankan UPDATE. Jika atribut kunci utama objek tidak diset atau jika UPDATE tidak memperbarui apapun, Django menjalankan sebuah INSERT.

Perlu dicatat bahwa ketika mereka mengatakan 'jika UPDATE tidak memperbarui apa pun', mereka pada dasarnya mengacu pada kasus di mana id yang Anda berikan objek tersebut belum ada dalam database.

Tom Manterfield
sumber
1

Jika salah satu masukan saat Anda membuat adalah kunci utama, ini sudah cukup:

Person.objects.get_or_create(id=1)

Ini akan diperbarui secara otomatis jika ada karena dua data dengan kunci utama yang sama tidak diperbolehkan.

Aminah Nuraini
sumber