sql >> データベース >  >> RDS >> PostgreSQL

Django:多対多のadd()中のIntegrityError

    エラーを再現できますか?

    はい、有名なPublicationを使用しましょう およびArticle Djangodocs のモデル 。次に、いくつかのスレッドを作成しましょう。

    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()
    

    バグレポート で報告されたタイプの一意のキー制約違反が必ず表示されます。 。それらが表示されない場合は、スレッドまたは反復の数を増やしてみてください。

    回避策はありますか?

    はい。 throughを使用する モデルとget_or_create 。これは、djangoドキュメントの例を応用したmodels.pyです。

    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')
    

    これは、上記のスレッドクラスを変更した新しいスレッドクラスです。

    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
    

    例外が表示されなくなったことがわかります。反復回数を自由に増やしてください。 get_or_createで1000までしか上がらなかった 例外はスローされませんでした。ただし、add() 通常、20回の反復で例外をスローしました。

    なぜこれが機能するのですか?

    get_or_create のため アトミックです。

    更新: スルーモデルを実際に排除できることを指摘してくれた@louisに感謝します。したがって、get_or_create MyThread2で として変更できます。

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


    1. MySQLでカーソルを使用する場合は、DECLAREステートメントからストアドプロシージャを呼び出します

    2. ダイナミックサンプリング12cで私を殺す

    3. 壊れたPL/ルビーの代替:倉庫ジャーナルテーブルを変換する

    4. mysql:特定のデータベースへの開いているすべての接続を表示しますか?