Có thể tái tạo lỗi không?
Có, hãy để chúng tôi sử dụng Publication
nổi tiếng và Article
mô hình từ tài liệu Django
. Sau đó, hãy tạo một vài chuỗi.
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()
Bạn chắc chắn thấy các vi phạm ràng buộc khóa duy nhất của loại được báo cáo trong báo cáo lỗi . Nếu bạn không thấy chúng, hãy thử tăng số lượng chuỗi hoặc số lần lặp lại.
Có công việc xung quanh không?
Đúng. Sử dụng through
mô hình và get_or_create
. Đây là mô hình.py được điều chỉnh từ ví dụ trong tài liệu 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')
Đây là lớp luồng mới là một sửa đổi của lớp ở trên.
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
Bạn sẽ thấy rằng ngoại lệ không còn hiển thị nữa. Hãy thoải mái tăng số lần lặp lại. Tôi chỉ đạt đến 1000 với get_or_create
nó không ném ra ngoại lệ. Tuy nhiên add()
thường đưa ra một ngoại lệ với 20 lần lặp lại.
Tại sao điều này hoạt động?
Bởi vì get_or_create là nguyên tử.
Cập nhật: Cảm ơn @louis đã chỉ ra rằng mô hình thông qua thực tế có thể bị loại bỏ. Bỏ get_or_create
trong MyThread2
có thể được thay đổi thành.
ap , c = article.publications.through.objects.get_or_create(
article=article, publication=pub)