Hrubá implementace stahování jako ZIP
This commit is contained in:
		
							parent
							
								
									aa364b3f49
								
							
						
					
					
						commit
						cd914f4524
					
				
					 2 changed files with 48 additions and 0 deletions
				
			
		|  | @ -11,7 +11,9 @@ urlpatterns = [ | |||
| 	path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='odevzdavatko_resitel_odevzdana_reseni'), | ||||
| 
 | ||||
| 	path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), | ||||
| 	path('org/reseni/zip/', org_required(views.OdevzdanaReseniVZipuView.as_view()), name='odevzdavatko_zip'), | ||||
| 	path('org/reseni/rocnik/<int:rocnik>/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'), | ||||
| 	path('org/reseni/rocnik/<int:rocnik>/zip/', org_required(views.OdevzdanaReseniVZipuView.as_view()), name='odevzdavatko_zip'), | ||||
| 	path('org/reseni/<int:problem>/<int:resitel>/', org_required(views.ReseniProblemuView.as_view()), name='odevzdavatko_reseni_resitele_k_problemu'), | ||||
| 	path('org/reseni/<int:pk>', org_required(viewMethodSwitch(get=views.EditReseniView.as_view(), post=views.hodnoceniReseniView)), name='odevzdavatko_detail_reseni'), | ||||
| 	path('org/reseni/all', org_required(views.SeznamReseniView.as_view())), | ||||
|  |  | |||
|  | @ -10,17 +10,22 @@ from django.shortcuts import redirect, get_object_or_404, render | |||
| from django.urls import reverse | ||||
| from django.db import transaction | ||||
| from django.db.models import Q | ||||
| from django.http import HttpResponse | ||||
| 
 | ||||
| from dataclasses import dataclass | ||||
| import datetime | ||||
| from decimal import Decimal | ||||
| from itertools import groupby | ||||
| import logging | ||||
| import os | ||||
| import tempfile | ||||
| import zipfile | ||||
| 
 | ||||
| from . import forms as f | ||||
| from .forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm | ||||
| from .models import Hodnoceni, Reseni | ||||
| 
 | ||||
| from odevzdavatko.templatetags.jmena import jmeno_jako_prefix | ||||
| from personalni.models import Resitel, Osoba, Organizator | ||||
| from tvorba.models import Problem, Deadline, Rocnik | ||||
| from tvorba.utils import resi_v_rocniku | ||||
|  | @ -175,6 +180,47 @@ class TabulkaOdevzdanychReseniView(ListView): | |||
| 
 | ||||
| 		return ctx | ||||
| 
 | ||||
| # Intuitivně se mi dědičnost nelíbí, neumím říct přesně proč… (Zhruba: | ||||
| # vykoná/přikládá se spousta kódu, který ale souvisí jen s HTML, tím, že si | ||||
| # píšeme vlastní .get(). Lepší by bylo společné ne-HTML části (e.g. | ||||
| # inicializuj_osy_tabulky) vyrazit ven a v obou  Views jen použít…) | ||||
| class OdevzdanaReseniVZipuView(TabulkaOdevzdanychReseniView): | ||||
| 	def get(self, request, *args, **kwargs): | ||||
| 		# Inspirováno implementací django.views.generic.list.BaseListView | ||||
| 		self.object_list = self.get_queryset() | ||||
| 		# Teď už máme i `self.problemy`. | ||||
| 		with tempfile.TemporaryDirectory() as d: | ||||
| 			print(f'DBG: {d=}') | ||||
| 			zfname = f"{d}/reseni.zip" | ||||
| 			with zipfile.ZipFile(zfname, 'w', compression=zipfile.ZIP_LZMA) as zf: # `zip` is builtin :-/ | ||||
| 				print(f'DBG:  .{self.reseni.count()=}') | ||||
| 				# TODO: data z tabulky | ||||
| 				for r in self.reseni: | ||||
| 					if len(r.resitele.all()) < 1: | ||||
| 						logger.error(f'Řešení {r.id} nemá řešitele??!!') | ||||
| 						continue | ||||
| 					# DBG! | ||||
| 					if len(r.prilohy.all()) < 1: continue | ||||
| 					# TODO: komentáře jmen souborů | ||||
| 					# Pro konzistenci imitujeme `data-alt-filename="{{object.resitele.first.osoba | jmeno_jako_prefix }}_{{ object.id }}_{{ priloha.split | last}}"` z templates/odevzdavatko/detail.html. | ||||
| 					jmeno_slozky = f'{jmeno_jako_prefix(r.resitele.first().osoba)}_{r.id}' | ||||
| 					zf.mkdir(jmeno_slozky) | ||||
| 					slozka = zipfile.Path(zf, jmeno_slozky) | ||||
| 					print(f'DBG:   .({jmeno_slozky=}, {r.prilohy.count()=})') | ||||
| 					for pr in r.prilohy.all(): | ||||
| 						jmeno_souboru = f'{jmeno_slozky}_{pr.split()[-1]}' | ||||
| 						print(f'DBG:    .({os.path.join(jmeno_slozky, jmeno_souboru)=})') | ||||
| 						zf.write(pr.soubor.path, os.path.join(jmeno_slozky, jmeno_souboru)) | ||||
| 
 | ||||
| 				print(f'DBG: Done, sending') | ||||
| 			# close&open k provedení všech zápisů | ||||
| 			with open(zfname, 'rb') as zf: | ||||
| 				print(f'DBG:  .') | ||||
| 				response = HttpResponse(zf.read(), content_type='application/zip') | ||||
| 				response['Content-Disposition'] = 'attachment; filename="reseni.zip"' | ||||
| 				print(f'DBG:   .') | ||||
| 				return response | ||||
| 
 | ||||
| # Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji? | ||||
| class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View): | ||||
| 	"""Rozskok mezi více řešeními téhož problému od téhož řešitele. | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Pavel "LEdoian" Turinsky
						Pavel "LEdoian" Turinsky