PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Django:IntegrityError selama Many To Many add()

Dapatkah kesalahan direproduksi?

Ya, mari kita gunakan Publication yang terkenal dan Article model dari Django docs . Kemudian, mari kita buat beberapa utas.

import threading
import random

def populate():

    for i in range(100):
        Article.objects.create(headline = 'headline{0}'.format(i))
        Publication.objects.create(title = 'title{0}'.format(i))

    print 'created objects'


class MyThread(threading.Thread):

    def run(self):
        for q in range(1,100):
            for i in range(1,5):
                pub = Publication.objects.all()[random.randint(1,2)]
                for j in range(1,5):
                    article = Article.objects.all()[random.randint(1,15)]
                    pub.article_set.add(article)

            print self.name


Article.objects.all().delete()
Publication.objects.all().delete()
populate()
thrd1 = MyThread()
thrd2 = MyThread()
thrd3 = MyThread()

thrd1.start()
thrd2.start()
thrd3.start()

Anda pasti melihat pelanggaran batasan kunci unik dari jenis yang dilaporkan dalam laporan bug . Jika Anda tidak melihatnya, coba tambah jumlah utas atau iterasi.

Apakah ada pekerjaan?

Ya. Gunakan through model dan get_or_create . Berikut adalah models.py yang diadaptasi dari contoh di django docs.

class Publication(models.Model):
    title = models.CharField(max_length=30)

    def __str__(self):              # __unicode__ on Python 2
        return self.title

    class Meta:
        ordering = ('title',)

class Article(models.Model):
    headline = models.CharField(max_length=100)
    publications = models.ManyToManyField(Publication, through='ArticlePublication')

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

    class Meta:
        ordering = ('headline',)

class ArticlePublication(models.Model):
    article = models.ForeignKey('Article', on_delete=models.CASCADE)
    publication = models.ForeignKey('Publication', on_delete=models.CASCADE)
    class Meta:
        unique_together = ('article','publication')

Ini adalah kelas threading baru yang merupakan modifikasi dari yang di atas.

class MyThread2(threading.Thread):

    def run(self):
        for q in range(1,100):
            for i in range(1,5):
                pub = Publication.objects.all()[random.randint(1,2)]
                for j in range(1,5):
                    article = Article.objects.all()[random.randint(1,15)]
                    ap , c = ArticlePublication.objects.get_or_create(article=article, publication=pub)
            print 'Get  or create', self.name

Anda akan menemukan bahwa pengecualian tidak lagi muncul. Jangan ragu untuk meningkatkan jumlah iterasi. Saya hanya naik ke 1000 dengan get_or_create itu tidak membuang pengecualian. Namun add() biasanya melemparkan pengecualian dengan dalam 20 iterasi.

Mengapa ini berhasil?

Karena get_or_create adalah atom.

Pembaruan: Terima kasih @louis telah menunjukkan bahwa model through sebenarnya dapat dihilangkan. Jadi get_or_create di MyThread2 dapat diubah sebagai.

ap , c = article.publications.through.objects.get_or_create(
            article=article, publication=pub)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ganti string dengan string lain dari daftar tergantung pada nilainya

  2. Paralelisme datang ke VAKUM

  3. psql mengembalikan 'anonim' dalam larik hasil

  4. Ubah kunci utama di tabel PostgreSQL

  5. PostgreSQL:ERROR:42601:daftar definisi kolom diperlukan untuk fungsi yang mengembalikan catatan