Source code for form.forms.named_file
from functools import cached_property
from onegov.form.fields import UploadField
from onegov.form import Form
from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Collection
[docs]
class NamedFileForm(Form):
""" Base class for handling database models using named files with forms.
Example::
class MyModel(AssociatedFiles):
pdf = NamedFile()
class MyForm(NamedFileForm):
pdf = UploadField('PDF')
@MyApp.form(model=MyCollection, form=MyForm, ...)
def add(self, request, form):
if form.submitted(request):
self.add(**form.get_useful_data())
...
...
@MyApp.form(model=MyModel, form=MyForm, ...)
def edit(self, request, form):
if form.submitted(request):
form.populate_obj(self)
...
form.process(obj=self)
...
"""
@cached_property
[docs]
def file_fields(self) -> dict[str, UploadField]:
return {
field.name: field for field in self
if isinstance(field, UploadField)
}
[docs]
def get_useful_data(
self,
exclude: 'Collection[str] | None' = None
) -> dict[str, Any]:
exclude = set(exclude or ())
exclude.update(self.file_fields.keys())
exclude.add('csrf_token')
data = super().get_useful_data(exclude=exclude)
for name, field in self.file_fields.items():
if field.data:
data[name] = (
field.file,
field.filename
)
return data
[docs]
def populate_obj(
self,
obj: object,
exclude: 'Collection[str] | None' = None,
include: 'Collection[str] | None' = None
) -> None:
exclude = set(exclude or ())
exclude.update(self.file_fields.keys())
super().populate_obj(
obj,
exclude=exclude,
include=include
)
for name, field in self.file_fields.items():
action = getattr(field, 'action', '')
if action == 'delete':
delattr(obj, name)
if action == 'replace' and field.data:
setattr(obj, name, (field.file, field.filename))
[docs]
def process_obj(self, obj: object) -> None:
super().process_obj(obj)
for name, field in self.file_fields.items():
file = getattr(obj, name)
if file:
field.data = {
'filename': file.reference.filename,
'size': file.reference.file.content_length,
'mimetype': file.reference.content_type
}