Добрый день. Есть некоторый код, который обрабатывает около 40К записей, под обработкой имеется ввиду запись в БД и на это уходит прилично много времени 50-60 минут. Может кто подскажет есть ли вариант оптимизировать данный код, а так же хотелось бы услышать критику по коду.
Алгоритм работы кода.
Первым шагом данные поступают в формате JSON (порциями по 3000 записей) в функцию productFill. Функция в свою очередь заполняет таблицу Product – если записи нету в таблице, то данные добавляются, а если данные есть и были изменения в некоторых полях, то изменяются.
Второй шаг - вызывается функция barcodeFill, которая добавляет данные в таблицу Barcode. Прежде чем добавить запись, проверяется есть ли запись с таким title уже в таблице и есть ли запись в таблице Product с соответствующим значением поля code
if not Barcode.objects.filter(title=item[1]):
if Product.objects.filter(code=item[0]):
Если условия выполняются данные добавляются в БД.
Третий шаг – вызывается функция countFill, алгоритм работы схож с алгоритмом функции productFill.
Может я немного замудрено расписал все, если есть вопросы могу ответить
*[23/Feb/2017 11:15:37] "POST /storageFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:16:44] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:18:33] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:21:00] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:24:14] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:28:04] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:32:22] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:37:46] "POST /productFill/ HTTP/1.1" 200 12
D:\djangoPRJ\izano\lib\site-packages\django\db\backends\mysql\base.py:110: Warning: (1265, "Data truncated for column 'title' at row 1548")
return self.cursor.execute(query, args)
[23/Feb/2017 11:43:19] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:49:14] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 11:56:32] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 12:04:40] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 12:04:40] "POST /productFill/ HTTP/1.1" 200 12
[23/Feb/2017 12:10:26] "POST /productFill/ HTTP/1.1" 200 12*
Модели:
from django.db import models
class Storage(models.Model):
code = models.CharField('Код', max_length=32, unique=True)
title = models.CharField('Наименование', max_length=128)
def __str__(self):
return self.title
class Meta():
verbose_name = 'Склад'
verbose_name_plural = 'Склады'
class Product(models.Model):
code = models.CharField('Код', max_length=32)
title = models.CharField('Наименование', max_length=128)
price_z = models.FloatField('Закупочная')
price_r = models.FloatField('Розничная')
price_o = models.FloatField('Оптовая')
last_update = models.DateTimeField('Обновление', auto_now=True)
def __str__(self):
return self.title
class Meta():
verbose_name = 'Товар'
verbose_name_plural = 'Товары'
class Barcode(models.Model):
product = models.ForeignKey(
Product, verbose_name='Товар', on_delete=models.CASCADE)
title = models.CharField('ШтрихКод', max_length=50, unique=True)
def __str__(self):
return self.title
class Meta():
verbose_name = 'Штрихкод'
verbose_name_plural = 'Штрихкоды'
class CountProduct(models.Model):
product = models.ForeignKey(
Product, verbose_name='Продукт', on_delete=models.CASCADE)
count = models.FloatField('Количество')
storage = models.ForeignKey(
Storage, verbose_name='Склад', on_delete=models.CASCADE)
def __str__(self):
return str(self.count)
class Meta():
verbose_name = 'Остаток'
verbose_name_plural = 'Остатки'
Views
def emptyStorage():
emptyS = Storage.objects.filter(code='z000')
if not emptyS:
emptyS = Storage(code='z000', title='EmptyStorage')
emptyS.save()
def unique(lst):
seen = set()
result = []
for x in lst:
if x.title in seen:
continue
seen.add(x.title)
result.append(x)
return result
@csrf_exempt
def storageFill(request):
try:
data = json.loads(request.body.decode("utf-8-sig"))
except ValueError:
return HttpResponse("invalid json")
data_list = data.get("storage_list")
emptyStorage()
storageArray = data_list
storageNew = []
storageUpdate = []
storageObj = {}
storageDB = Storage.objects.all()
for st in storageDB:
storageObj[st.code] = st
with transaction.atomic():
for item in storageArray:
if item[0] in storageObj:
st = storageObj[item[0]]
st.title = item[1]
storageUpdate.append(st)
else:
st = Storage(code=item[0], title=item[1])
storageNew.append(st)
Storage.objects.bulk_create(storageNew)
bulk_update(storageUpdate)
return HttpResponse('storage - ok')
@csrf_exempt
def barcodeFill(data_list):
newCode = []
with transaction.atomic():
for item in data_list:
if len(item[1])>0:
if not Barcode.objects.filter(title=item[1]):
if Product.objects.filter(code=item[0]):
pr = Product.objects.filter(code=item[0])[0]
newBar = Barcode(title=item[1], product=pr)
newCode.append(newBar)
Barcode.objects.bulk_create(unique(newCode))
return HttpResponse('barc0de - ok')
@csrf_exempt
def countFill(data_list):
storageObj = {}
countUpdate = []
countNew = []
storageDB = Storage.objects.all()
for item in storageDB:
storageObj[item.code] = item
with transaction.atomic():
for item in data_list:
query = CountProduct.objects.filter(product__code=item[0], storage__code=item[7])
if query:
updateC = query[0]
updateC.count = item[3]
countUpdate.append(updateC)
else:
if Product.objects.filter(code=item[0]):
pr = Product.objects.filter(code=item[0])[0]
newC = CountProduct(product=pr, count=item[3], storage=storageObj[item[7]])
countNew.append(newC)
CountProduct.objects.bulk_create(countNew)
bulk_update(countUpdate, update_fields=['count'])
return HttpResponse("count_product - ok")
@csrf_exempt
def productFill(request):
try:
data = json.loads(request.body.decode("utf-8-sig"))
except ValueError:
return HttpResponse("invalid json")
productArray = data.get("product_list")
productNew = [] # Товар который надо добавить
# Товар который надо обновить (Наименование, ценны, количество, штрихкод)
productUpdated = []
productNotChanged = [] # Товар у которого надо обновить время
# Словарь товаров из БД вместо ключа КОД товара {"001": ["001", "Товар 1",
# 10, 11, 12, 0.4], ....}
productObj = {}
timeNow = timezone.now()
cacheCodeNewProduct = []
productDB = Product.objects.all()
for prdct in productDB:
productObj[prdct.code] = prdct
with transaction.atomic():
for item in productArray:
if item[0] in productObj:
prdct = productObj[item[0]]
if item[2] != prdct.title or item[4] != prdct.price_z or item[5] != prdct.price_r or item[6] != prdct.price_o:
prdct.title = item[2]
prdct.price_z = item[4]
prdct.price_r = item[5]
prdct.price_o = item[6]
prdct.last_update = timeNow
productUpdated.append(prdct)
else:
prdct.last_update = timeNow
productNotChanged.append(prdct)
else:
prdct = Product(code=item[0], title=item[2], price_z=item[
4], price_r=item[5], price_o=item[6], last_update=timeNow)
productNew.append(prdct)
Product.objects.bulk_create(unique(productNew))
bulk_update(unique(productUpdated))
productNotChanged=unique(productNotChanged)
bulk_update((productNotChanged), update_fields=["last_update"])
barcodeFill(productArray)
countFill(productArray)
return HttpResponse("product - ok")
Формат данных такой:
{"product_list": [ ["00000034662", "5050370302780", "Чайник Электрич. SCARLETT SC-EK21S06",
1.00,1369.58,1650.00,0.00,"000000001"], ["00000034662", "5050370302780", "Чайник Электрич. SCARLETT SC-EK21S06",
5.00,1369.58,1650.00,0.00,"000000002"], ["00000034663", "5050370002826", "Чайник Электрич. SCARLETT SC-028",
1.00,1247.38,1500.00,0.00,"000000001"], ["00000034663", "5050370002826", "Чайник Электрич. SCARLETT SC-028",
2.00,1247.38,1500.00,0.00,"000000002"], ["00000034664", "5050370306429", "Чайник Электрич. SCARLETT SC-EK27G08",
1.00,1219.18,1470.00,0.00,"000000001"], ["00000034664", "5050370306429", "Чайник Электрич. SCARLETT SC-EK27G08",
5.00,1219.18,1470.00,0.00,"000000002"], ["00000034665", "5050370305781", "Чайник Электрич. SCARLETT SC-EK21S25",
1.00,715.34,860.00,0.00,"000000001"], ["00000034665", "5050370305781", "Чайник Электрич. SCARLETT SC-EK21S25",
5.00,715.34,860.00,0.00,"000000002"], ["00000034666", "5050370306931", "Чайник Электрич. SCARLETT SC-EK27G15",
1.00,1185.34,1430.00,0.00,"000000003"], ["00000034666", "5050370306931", "Чайник Электрич. SCARLETT SC-EK27G15",
4.00,1185.34,1430.00,0.00,"000000002"],
Updated 23 Feb. 2017, 12:19 by NewPerson.