Add v2 registry uploads and source CSV exports
This commit is contained in:
39
src/apps/parsers/api_v2_urls.py
Normal file
39
src/apps/parsers/api_v2_urls.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""API v2 routes for parser source exports."""
|
||||
|
||||
from apps.parsers.models import ParserLoadLog
|
||||
from apps.parsers.source_registry import PARSER_SOURCES, ParserSourceDescriptor
|
||||
from apps.parsers.views import SourceResultCsvDownloadView
|
||||
from django.urls import path
|
||||
|
||||
app_name = "parser_sources"
|
||||
|
||||
|
||||
def _download_source_descriptors():
|
||||
"""Return unique source result routes that support CSV download."""
|
||||
seen_routes = set()
|
||||
for descriptor in PARSER_SOURCES.values():
|
||||
if not descriptor.api_route or descriptor.api_route in seen_routes:
|
||||
continue
|
||||
seen_routes.add(descriptor.api_route)
|
||||
if descriptor.source == ParserLoadLog.Source.FNS_REPORTS:
|
||||
continue
|
||||
yield descriptor
|
||||
|
||||
|
||||
def _download_view(descriptor: ParserSourceDescriptor):
|
||||
class SourceDownloadView(SourceResultCsvDownloadView):
|
||||
source_key = descriptor.key
|
||||
|
||||
return SourceDownloadView.as_view()
|
||||
|
||||
|
||||
urlpatterns = []
|
||||
for source_descriptor in _download_source_descriptors():
|
||||
route_name = source_descriptor.api_route.replace("/", "-")
|
||||
urlpatterns.append(
|
||||
path(
|
||||
f"{source_descriptor.api_route}/download/",
|
||||
_download_view(source_descriptor),
|
||||
name=f"{route_name}-download",
|
||||
)
|
||||
)
|
||||
@@ -520,6 +520,7 @@ class ParserSourceSerializer(serializers.Serializer):
|
||||
parser_strategy = serializers.CharField()
|
||||
source_notes = serializers.CharField(allow_blank=True)
|
||||
supports_file_upload = serializers.BooleanField()
|
||||
api_route = serializers.CharField(allow_blank=True)
|
||||
result_list_url = serializers.CharField()
|
||||
result_detail_url = serializers.CharField()
|
||||
upload_url = serializers.CharField(allow_blank=True)
|
||||
|
||||
@@ -2295,6 +2295,79 @@ class SourceResultListView(APIView):
|
||||
)
|
||||
|
||||
|
||||
SOURCE_CSV_HEADERS = [
|
||||
"id",
|
||||
"load_batch",
|
||||
"source",
|
||||
"external_id",
|
||||
"inn",
|
||||
"ogrn",
|
||||
"organisation_name",
|
||||
"title",
|
||||
"record_date",
|
||||
"amount",
|
||||
"status",
|
||||
"url",
|
||||
"payload",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
|
||||
def _csv_cell(value) -> str:
|
||||
if value is None:
|
||||
return ""
|
||||
if isinstance(value, dict):
|
||||
return json.dumps(value, ensure_ascii=False, sort_keys=True)
|
||||
if hasattr(value, "isoformat"):
|
||||
return value.isoformat()
|
||||
return str(value)
|
||||
|
||||
|
||||
def _source_csv_filename(descriptor) -> str:
|
||||
route_name = descriptor.api_route.replace("/", "-") or descriptor.key
|
||||
return f"{get_valid_filename(route_name)}.csv"
|
||||
|
||||
|
||||
class SourceResultCsvDownloadView(APIView):
|
||||
"""CSV download результата конкретного источника API v2."""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
source_key = ""
|
||||
|
||||
def get(self, request: Request, source_key: str | None = None):
|
||||
resolved_source_key = source_key or self.source_key
|
||||
query_serializer = ParserResultQuerySerializer(data=request.query_params)
|
||||
query_serializer.is_valid(raise_exception=True)
|
||||
params = query_serializer.validated_data
|
||||
params["include_payload"] = True
|
||||
|
||||
descriptor, queryset = _filter_result_queryset(resolved_source_key, params)
|
||||
if descriptor is None:
|
||||
return _source_not_found_response(resolved_source_key)
|
||||
if descriptor.source == ParserLoadLog.Source.FNS_REPORTS:
|
||||
return _source_not_found_response(resolved_source_key)
|
||||
|
||||
response = HttpResponse(content_type="text/csv; charset=utf-8")
|
||||
response[
|
||||
"Content-Disposition"
|
||||
] = f'attachment; filename="{_source_csv_filename(descriptor)}"'
|
||||
|
||||
writer = csv.writer(response)
|
||||
writer.writerow(SOURCE_CSV_HEADERS)
|
||||
for record in queryset.iterator(chunk_size=1000):
|
||||
row = _result_record_to_dict(
|
||||
descriptor.source,
|
||||
record,
|
||||
include_payload=True,
|
||||
)
|
||||
writer.writerow(
|
||||
[_csv_cell(row.get(header)) for header in SOURCE_CSV_HEADERS]
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
class SourceResultDetailView(APIView):
|
||||
"""GET одной записи результата источника."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user