diff --git a/dynamicforms/admin.py b/dynamicforms/admin.py
index 7fe434eecefdae8ab0f387c361d70677287e7063..175bb05dfdee389f3a4c895a4a7ff776953818b3 100644
--- a/dynamicforms/admin.py
+++ b/dynamicforms/admin.py
@@ -42,7 +42,7 @@ class FormAdmin(admin.ModelAdmin):
 
     def download_csv(self, request, queryset):
         """Download entries of selected forms under a ZIP file."""
-        return download_multiple_forms_entries(request, queryset)
+        return download_multiple_forms_entries(request, forms=queryset.all())
 
     download_csv.short_description = (
         'Télécharger les résponses des formulaires sélectionnés')
diff --git a/dynamicforms/exports.py b/dynamicforms/exports.py
index 2169840db43b4cb05cc67dac44948fee5df9f722..b1dacf7a1d14403c7974242d2c816062033f948a 100644
--- a/dynamicforms/exports.py
+++ b/dynamicforms/exports.py
@@ -53,8 +53,8 @@ def _write_csv(form: Form, stream):
     return stream
 
 
-def write_zip(forms_queryset, stream=None, folder='forms'):
-    """Write form entries into a zip of CSV files."""
+def write_zip(forms, stream=None, folder='forms'):
+    """Write forms' entries into a zip of CSV files."""
     if stream is None:
         stream = BytesIO()
     # See https://stackoverflow.com/a/32075279
@@ -63,7 +63,7 @@ def write_zip(forms_queryset, stream=None, folder='forms'):
         'consider using BytesIO instead'
     )
     with zipfile.ZipFile(stream, 'w') as zip:
-        for form in forms_queryset:
+        for form in forms:
             csv_file = StringIO()
             _write_csv(form, csv_file)
             csv_filename = os.path.join(folder, f'{form.slug}.csv')
diff --git a/dynamicforms/views.py b/dynamicforms/views.py
index 498963b0f532c4cc0244136ff8529c248593bee0..a257292e4171a9551123202d711a78245b69fe1e 100644
--- a/dynamicforms/views.py
+++ b/dynamicforms/views.py
@@ -28,12 +28,13 @@ class FormEntryViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
     queryset = FormEntry.objects.all()
 
 
-def download_multiple_forms_entries(request, queryset):
+def download_multiple_forms_entries(request, forms):
     """Download form entries in a ZIP file containing CSV files.
 
-    Note: this is not a proper Django view as it expects a queryset.
+    Note: this is not a proper Django view as it expects an iterable of
+    Form objects (typically a queryset).
     """
-    stream = write_zip(queryset, folder='reponses')
+    stream = write_zip(forms=forms, folder='reponses')
     stream.seek(0)
     contents = stream.read()
     filename = 'responses.zip'
diff --git a/projects/admin.py b/projects/admin.py
index 341c647b5619dfe54598015d1b634cfe606cd231..2cdb4266757018f0fb6555f001160b373f76d267 100644
--- a/projects/admin.py
+++ b/projects/admin.py
@@ -2,6 +2,8 @@
 
 from django.contrib import admin
 
+from dynamicforms.views import download_multiple_forms_entries
+from dynamicforms.models import Form
 from .models import Edition, Participation, Project, EditionForm
 
 
@@ -78,6 +80,17 @@ class EditionFormAdmin(admin.ModelAdmin):
     list_display = ('form', 'deadline', 'recipient',)
     list_filter = ('edition', 'deadline',)
 
+    actions = ['download_csv']
+
+    def download_csv(self, request, queryset):
+        """Download entries of selected edition forms under a ZIP file."""
+        form_ids = queryset.values_list('form__id', flat=True)
+        forms = Form.objects.filter(id__in=form_ids)
+        return download_multiple_forms_entries(request, forms=forms)
+
+    download_csv.short_description = (
+        'Télécharger les résponses des formulaires sélectionnés')
+
 
 @admin.register(Participation)
 class ParticipationAdmin(admin.ModelAdmin):