Skip to content
Snippets Groups Projects
Commit 40ef73ba authored by florimondmanca's avatar florimondmanca
Browse files

add support for files on dynamic forms

parent 27d618a4
No related branches found
No related tags found
No related merge requests found
"""Dynamic forms admin panels."""
from django.contrib import admin
from .models import Form, Section, Question, FormEntry, Answer
from .models import Form, Section, Question, FormEntry, Answer, File
class SectionInline(admin.StackedInline):
......@@ -18,14 +18,22 @@ class QuestionInline(admin.StackedInline):
extra = 0
class FileInline(admin.TabularInline):
"""Inline for form files."""
model = File
extra = 0
@admin.register(Form)
class FormAdmin(admin.ModelAdmin):
"""Admin panel for forms."""
list_display = ('title', 'created',)
list_filter = ('created',)
readonly_fields = ('slug',)
search_fields = ('title',)
inlines = (SectionInline,)
inlines = (SectionInline, FileInline,)
@admin.register(Section)
......@@ -63,3 +71,12 @@ class AnswerAdmin(admin.ModelAdmin):
list_display = ('answer', 'question', 'entry')
list_filter = ('entry__form',)
search_fields = ('answer', 'question__text',)
@admin.register(File)
class FileAdmin(admin.ModelAdmin):
"""Admin panel for form files."""
list_display = ('name', 'file', 'form')
list_filter = ('form',)
search_fields = ('name',)
# Generated by Django 2.0.6 on 2018-06-15 23:05
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dynamicforms', '0008_auto_20180616_0007'),
]
operations = [
migrations.CreateModel(
name='File',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=300, verbose_name='nom')),
('file', models.FileField(upload_to='forms/attachments/', verbose_name='fichier')),
('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='dynamicforms.Form', verbose_name='formulaire')),
],
options={
'verbose_name': 'fichier',
'verbose_name_plural': 'fichiers',
},
),
migrations.AlterField(
model_name='question',
name='type',
field=models.CharField(choices=[('text-small', 'Texte court'), ('text-small', 'Texte long'), ('yes-no', 'Oui/Non'), ('date', 'Date'), ('sex', 'Sexe')], max_length=100, verbose_name='type de question'),
),
]
# Generated by Django 2.0.6 on 2018-06-15 23:21
from django.db import migrations, models
import dynamicforms.utils
class Migration(migrations.Migration):
dependencies = [
('dynamicforms', '0009_auto_20180616_0105'),
]
operations = [
migrations.AddField(
model_name='form',
name='slug',
field=models.SlugField(default='noname', max_length=100),
),
migrations.AlterField(
model_name='file',
name='file',
field=models.FileField(upload_to=dynamicforms.utils.file_upload_to, verbose_name='fichier'),
),
]
......@@ -10,28 +10,35 @@ A user can reply to a form by submitting a form entry, made of
multiple answers (one per question).
"""
from django.utils.text import Truncator
from django.db import models
from django.utils.text import Truncator, slugify
from .utils import file_upload_to
class Form(models.Model):
"""Represents a form with multiple questions."""
title = models.CharField('titre', max_length=300)
slug = models.SlugField(max_length=100, blank=True, default='')
created = models.DateTimeField('créé le', auto_now_add=True)
class Meta: # noqa
ordering = ('-created',)
verbose_name = 'formulaire'
def clean(self):
if not self.pk:
self.slug = slugify(self.title)
def __str__(self):
return str(self.title)
@property
def entries_count(self) -> int:
"""Return the number of entries in this form."""
return self.entries.count()
def __str__(self):
return str(self.title)
class Section(models.Model):
"""Represents a group of related questions."""
......@@ -117,3 +124,20 @@ class Answer(models.Model):
def __str__(self):
answer = Truncator(self.answer).chars(140)
return f'{self.question} : {answer}'
class File(models.Model):
"""Represents a file downloadable by form respondants."""
name = models.CharField('nom', max_length=300)
file = models.FileField('fichier', upload_to=file_upload_to)
form = models.ForeignKey(
'Form', on_delete=models.CASCADE, related_name='files',
verbose_name='formulaire')
class Meta: # noqa
verbose_name = 'fichier'
verbose_name_plural = 'fichiers'
def __str__(self):
return str(self.name)
"""Dynamic forms serializers."""
from rest_framework import serializers
from .models import Form, Section, Question, Answer, FormEntry
from .models import Form, Section, Question, Answer, FormEntry, File
class QuestionSerializer(serializers.ModelSerializer):
......@@ -19,7 +19,15 @@ class SectionSerializer(serializers.ModelSerializer):
class Meta: # noqa
model = Section
fields = ('id', 'title', 'questions',)
fields = ('id', 'title', 'questions', 'form')
class FileSerializer(serializers.ModelSerializer):
"""Serializer for form files."""
class Meta: # noqa
model = File
fields = ('id', 'name', 'file', 'form')
class FormSerializer(serializers.HyperlinkedModelSerializer):
......@@ -27,7 +35,7 @@ class FormSerializer(serializers.HyperlinkedModelSerializer):
class Meta: # noqa
model = Form
fields = ('id', 'url', 'title', 'entries_count',)
fields = ('id', 'url', 'slug', 'title', 'entries_count',)
extra_kwargs = {
'url': {'view_name': 'api:form-detail'},
}
......@@ -37,9 +45,10 @@ class FormDetailSerializer(FormSerializer):
"""Serializer for form detail."""
sections = SectionSerializer(many=True)
files = FileSerializer(many=True)
class Meta(FormSerializer.Meta): # noqa
fields = FormSerializer.Meta.fields + ('sections',)
fields = FormSerializer.Meta.fields + ('sections', 'files',)
class AnswerSerializer(serializers.ModelSerializer):
......
"""Dynamic forms utilities."""
import os
def file_upload_to(instance: 'File', filename: str) -> str:
"""Return the upload path to a form file."""
return os.path.join('forms', 'files', instance.form.title, filename)
......@@ -88,6 +88,14 @@ class Edition(models.Model):
return s
# class EditionForm(models.Model):
# """Participation form to a project's edition."""
#
# form = models.ForeignKey(
# 'dyanmicforms.Form', on_delete=models.CASCADE,
# verbose_name='formulaire')
class ParticipationQuerySet(models.QuerySet):
"""Custom QuerySet for participations."""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment