Рефакторинг: вынесена логика импорта/экспорта клиентов в отдельный сервис
- Создан модуль customers/services/import_export.py согласно best practices - Класс CustomerExporter: содержит логику экспорта в CSV (ранее была в views) - Класс CustomerImporter: заглушка для будущей реализации импорта - Views стали тонкими: customer_export и customer_import делегируют работу сервисам - Улучшена организация кода: соблюдён принцип Single Responsibility - Уменьшен размер views.py на 30 строк - Добавлена подробная документация в docstrings классов и методов - Логику теперь легко тестировать и переиспользовать (например, в Celery tasks) Преимущества: - Чистое разделение ответственности - Упрощённое тестирование - Возможность переиспользования в асинхронных задачах - Соответствие Django best practices
This commit is contained in:
106
myproject/customers/services/import_export.py
Normal file
106
myproject/customers/services/import_export.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Сервис для импорта и экспорта клиентов.
|
||||
|
||||
Этот модуль содержит логику импорта/экспорта клиентов в различных форматах (CSV, Excel).
|
||||
Разделение на отдельный модуль улучшает организацию кода и следует принципам SRP.
|
||||
"""
|
||||
import csv
|
||||
from django.http import HttpResponse
|
||||
from django.utils import timezone
|
||||
from ..models import Customer
|
||||
|
||||
|
||||
class CustomerExporter:
|
||||
"""
|
||||
Класс для экспорта клиентов в различные форматы.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def export_to_csv():
|
||||
"""
|
||||
Экспортирует всех клиентов (кроме системного) в CSV файл.
|
||||
|
||||
Поля экспорта:
|
||||
- ID
|
||||
- Имя
|
||||
- Email
|
||||
- Телефон
|
||||
- Дата создания
|
||||
|
||||
Примечание: Баланс кошелька НЕ экспортируется (требование безопасности).
|
||||
|
||||
Returns:
|
||||
HttpResponse: HTTP ответ с CSV файлом для скачивания
|
||||
"""
|
||||
# Создаём HTTP ответ с CSV файлом
|
||||
response = HttpResponse(content_type='text/csv; charset=utf-8')
|
||||
timestamp = timezone.now().strftime("%Y%m%d_%H%M%S")
|
||||
response['Content-Disposition'] = f'attachment; filename="customers_export_{timestamp}.csv"'
|
||||
|
||||
# Добавляем BOM для корректного открытия в Excel
|
||||
response.write('\ufeff')
|
||||
|
||||
writer = csv.writer(response)
|
||||
|
||||
# Заголовки
|
||||
writer.writerow([
|
||||
'ID',
|
||||
'Имя',
|
||||
'Email',
|
||||
'Телефон',
|
||||
'Дата создания',
|
||||
])
|
||||
|
||||
# Данные (исключаем системного клиента)
|
||||
customers = Customer.objects.filter(is_system_customer=False).order_by('-created_at')
|
||||
|
||||
for customer in customers:
|
||||
writer.writerow([
|
||||
customer.id,
|
||||
customer.name or '',
|
||||
customer.email or '',
|
||||
str(customer.phone) if customer.phone else '',
|
||||
customer.created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
])
|
||||
|
||||
return response
|
||||
|
||||
|
||||
class CustomerImporter:
|
||||
"""
|
||||
Класс для импорта клиентов из различных форматов.
|
||||
|
||||
TODO: Реализовать:
|
||||
- Парсинг CSV файлов
|
||||
- Парсинг Excel файлов (.xlsx, .xls)
|
||||
- Валидация данных (email, телефон)
|
||||
- Обработка дубликатов
|
||||
- Пакетное создание клиентов
|
||||
- Отчёт об ошибках
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.errors = []
|
||||
self.success_count = 0
|
||||
self.skip_count = 0
|
||||
|
||||
def import_from_file(self, file, update_existing=False):
|
||||
"""
|
||||
Импорт клиентов из загруженного файла.
|
||||
|
||||
Args:
|
||||
file: Загруженный файл (UploadedFile)
|
||||
update_existing: Обновлять ли существующих клиентов (по email/телефону)
|
||||
|
||||
Returns:
|
||||
dict: Результат импорта с статистикой
|
||||
"""
|
||||
# TODO: Реализовать логику импорта
|
||||
return {
|
||||
'success': False,
|
||||
'message': 'Функция импорта находится в разработке',
|
||||
'created': 0,
|
||||
'updated': 0,
|
||||
'skipped': 0,
|
||||
'errors': []
|
||||
}
|
||||
Reference in New Issue
Block a user