sql >> Database teknologi >  >> RDS >> PostgreSQL

Django:IntegrityError under Many To Many add()

Kan fejlen gengives?

Ja, lad os bruge den berømte Publication og Article modeller fra Django docs . Lad os derefter oprette et par tråde.

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

Du er sikker på at se unikke overtrædelser af nøglebegrænsninger af den type, der er rapporteret i fejlrapporten . Hvis du ikke kan se dem, så prøv at øge antallet af tråde eller iterationer.

Er der en løsning?

Ja. Brug through modeller og get_or_create . Her er models.py tilpasset fra eksemplet i 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')

Her er den nye trådningsklasse, som er en modifikation af den ovenfor.

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

Du vil opdage, at undtagelsen ikke længere dukker op. Øg gerne antallet af iterationer. Jeg gik kun op til 1000 med get_or_create det gav ikke undtagelsen. Dog add() normalt kastede en undtagelse med i 20 iterationer.

Hvorfor virker dette?

Fordi get_or_create er atomart.

Opdatering: Tak @louis for at påpege, at den gennemgående model faktisk kan elimineres. Således get_or_create i MyThread2 kan ændres som.

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


  1. Problem med $_POST, if isset() og mysql_fetch_assoc():ekko returnerer korrekt værdi, sidekilde returnerer altid anden værdi

  2. Indsæt data i SQL Server 2017

  3. Best Practices for PostgreSQL-revisionslogning

  4. Oracle til SQL2005 DATETIME-feltet løber over i SSIS