PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Django:IntegrityError по време на много към много add()

Може ли грешката да бъде възпроизведена?

Да, нека използваме известната Publication и Article модели от документи на Django . След това нека създадем няколко теми.

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 . Ето models.py, адаптиран от примера в документите на django.

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

Ще откриете, че изключението вече не се показва. Чувствайте се свободни да увеличите броя на повторенията. Стигнах само до 1000 с get_or_create не хвърли изключение. Въпреки това add() обикновено хвърля изключение с 20 итерации.

Защо това работи?

Тъй като get_or_create е атомно.

Актуализация: Благодаря на @louis, че посочи, че моделът на преминаване всъщност може да бъде премахнат. По този начин get_or_create в MyThread2 може да се промени като.

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. Как да изберете с помощта на клауза WITH RECURSIVE

  2. Как да изобразите едно към много релации към XML с PostgreSQL

  3. Как да споделяте таблица между множество бази данни на Postgresql

  4. Търсене в пълен текст от PostgreSQL 8.3

  5. Какъв тип данни за географска ширина и дължина?