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('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/', 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>/', 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: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/<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())), | 	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.urls import reverse | ||||||
| from django.db import transaction | from django.db import transaction | ||||||
| from django.db.models import Q | from django.db.models import Q | ||||||
|  | from django.http import HttpResponse | ||||||
| 
 | 
 | ||||||
| from dataclasses import dataclass | from dataclasses import dataclass | ||||||
| import datetime | import datetime | ||||||
| from decimal import Decimal | from decimal import Decimal | ||||||
| from itertools import groupby | from itertools import groupby | ||||||
| import logging | import logging | ||||||
|  | import os | ||||||
|  | import tempfile | ||||||
|  | import zipfile | ||||||
| 
 | 
 | ||||||
| from . import forms as f | from . import forms as f | ||||||
| from .forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm | from .forms import OdevzdavatkoTabulkaFiltrForm as FiltrForm | ||||||
| from .models import Hodnoceni, Reseni | from .models import Hodnoceni, Reseni | ||||||
| 
 | 
 | ||||||
|  | from odevzdavatko.templatetags.jmena import jmeno_jako_prefix | ||||||
| from personalni.models import Resitel, Osoba, Organizator | from personalni.models import Resitel, Osoba, Organizator | ||||||
| from tvorba.models import Problem, Deadline, Rocnik | from tvorba.models import Problem, Deadline, Rocnik | ||||||
| from tvorba.utils import resi_v_rocniku | from tvorba.utils import resi_v_rocniku | ||||||
|  | @ -175,6 +180,47 @@ class TabulkaOdevzdanychReseniView(ListView): | ||||||
| 
 | 
 | ||||||
| 		return ctx | 		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? | # Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji? | ||||||
| class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View): | class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View): | ||||||
| 	"""Rozskok mezi více řešeními téhož problému od téhož řešitele. | 	"""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