Объекты отсутствуют в БД (проблема транзакции)
У меня есть представление DRF
, которое импортирует Product
объекты в базе данных. Проблема в том, что пока транзакция жива, все выглядит правильно. Созданные объекты имеют свои ids
(значит они были сохранены в БД).
Проблема в том, что после того, как представление возвращает ответ, эти объекты больше не присутствуют в базе данных.
- get file (binary from request)
- store it in
/tmp/product_imports/
- call
ImportService.import_csv(new_filepath)
- the method returns a number of products imported
- return a response from the view
Все выглядит хорошо, view
возвращает число (2 в моем случае, так как 3 из 5 продуктов не действительны). Но когда я проверяю БД, его там нет
@action(methods=['post'], detail=False)
def import_csv(self, request, pk=None) -> Response:
csv_file = request.FILES['file']
csv_import_files_dir = os.path.join('/tmp/project_imports/')
csv_file_path = os.path.join(csv_import_files_dir, str(uuid.uuid4()))
os.makedirs(csv_import_files_dir, exist_ok=True)
with open(csv_file_path, 'wb') as f:
f.write(csv_file.read())
count = product_services.imports.ImportService.import_csv(csv_file_path, request.user)
return Response({'imported': count})
Основные методы из ImportService
@classmethod
def import_csv(cls, filepath: str, created_by: User, delete_file=True) -> int:
"""imports products
supplier_sku already exists ? skip product : add product """
cls.validate_csv(filepath)
products_count = 0
with open(filepath) as f:
reader = csv.DictReader(f)
for row in reader:
if not all([row.get(field, None) is not None for field in ['title', 'sku']]):
continue
row['title'] = row['title'][:99]
try:
cls.create_from_dict(row, created_by)
except IntegrityError:
raise # todo what?
except cls.InvalidCSVRowException:
continue
except:
continue
else:
products_count += 1
if delete_file:
os.remove(filepath)
return products_count
class InvalidCSVRowException(Exception):
pass
@classmethod
def validate_row(cls, row: dict):
if not all([row.get(field, None) for field in cls.REQUIRED_COLUMNS]):
raise cls.InvalidCSVRowException(f"These columns can't be empty: {cls.REQUIRED_COLUMNS} | {row}")
@classmethod
def create_from_dict(cls, row: dict, created_by):
# ['supplier', 'sku', 'url', 'title', 'price']
from products.models import Product
from products.models import ProductInfo
cls.validate_row(row)
product = Product(created_by=created_by, product_title=row['title'])
product.save()
product_id = product.id
from suppliers.models import Supplier
supplier = \
Supplier.objects.get_or_create(name__iexact=row['supplier'], defaults={'name': row['supplier']})[
0]
product_info = ProductInfo(product_id=product_id, supplier=supplier, supplier_sku=row['sku'],
supplier_url=row['url'], supplier_title=row['title'], current_price=row['price'])
product_info.save()
PS: Я заметил, что когда я останавливаю выполнение (в отладчике) до того, как представление вернет ответ, я не могу запросить продукты из базы данных, так как это вызывает:
You can't execute queries until the end of 'atomic' block
. Да, есть ATOMIC_REQUESTS=True
.