DetailForm: Use Meta class instead
Instead of class attributes, make a generic reusable the FormOption class and update the DetailForm to use a Meta class for options. Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import os
|
|||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.admin.utils import label_for_field
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
@@ -13,7 +14,7 @@ from mayan.apps.acls.models import AccessControlList
|
|||||||
|
|
||||||
from .classes import Package
|
from .classes import Package
|
||||||
from .models import UserLocaleProfile
|
from .models import UserLocaleProfile
|
||||||
from .utils import resolve_attribute
|
from .utils import introspect_attribute, resolve_attribute
|
||||||
from .widgets import DisableableSelectWidget, PlainWidget, TextAreaDiv
|
from .widgets import DisableableSelectWidget, PlainWidget, TextAreaDiv
|
||||||
|
|
||||||
|
|
||||||
@@ -41,26 +42,89 @@ class ChoiceForm(forms.Form):
|
|||||||
selection = forms.MultipleChoiceField(widget=DisableableSelectWidget())
|
selection = forms.MultipleChoiceField(widget=DisableableSelectWidget())
|
||||||
|
|
||||||
|
|
||||||
|
class FormOptions(object):
|
||||||
|
def __init__(self, form, kwargs, options=None):
|
||||||
|
"""
|
||||||
|
Option definitions will be iterated. The option value will be
|
||||||
|
determined in the following order: as passed via keyword
|
||||||
|
arguments during form intialization, as form get_... method or
|
||||||
|
finally as static Meta options. This is to allow a form with
|
||||||
|
Meta options or method to be overrided at initialization
|
||||||
|
and increase the usability of a single class.
|
||||||
|
"""
|
||||||
|
for option_definition in self.option_definitions:
|
||||||
|
name = option_definition.keys()[0]
|
||||||
|
default_value = option_definition.values()[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check for a runtime value via kwargs
|
||||||
|
value = kwargs.pop(name)
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
# Check if there is a get_... method
|
||||||
|
value = getattr(self, 'get_{}'.format(name))()
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
# Check the meta class options
|
||||||
|
value = getattr(options, name)
|
||||||
|
except AttributeError:
|
||||||
|
value = default_value
|
||||||
|
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
|
||||||
|
class DetailFormOption(FormOptions):
|
||||||
|
# Dictionary list of option names and default values
|
||||||
|
option_definitions = (
|
||||||
|
{'extra_fields': []},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DetailForm(forms.ModelForm):
|
class DetailForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.extra_fields = kwargs.pop('extra_fields', ())
|
self.opts = DetailFormOption(
|
||||||
|
form=self, kwargs=kwargs, options=getattr(self, 'Meta', None)
|
||||||
|
)
|
||||||
super(DetailForm, self).__init__(*args, **kwargs)
|
super(DetailForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
for extra_field in self.extra_fields:
|
for extra_field in self.opts.extra_fields:
|
||||||
result = resolve_attribute(obj=self.instance, attribute=extra_field['field'])
|
obj = extra_field.get('object', self.instance)
|
||||||
label = 'label' in extra_field and extra_field['label'] or None
|
field = extra_field['field']
|
||||||
|
|
||||||
|
result = resolve_attribute(
|
||||||
|
attribute=field, obj=obj
|
||||||
|
)
|
||||||
|
|
||||||
|
label = extra_field.get('label', None)
|
||||||
|
|
||||||
|
if not label:
|
||||||
|
attribute_name, obj = introspect_attribute(
|
||||||
|
attribute_name=field, obj=obj
|
||||||
|
)
|
||||||
|
|
||||||
|
if not obj:
|
||||||
|
label = _('None')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
label = getattr(
|
||||||
|
getattr(obj, attribute_name), 'short_description'
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
label = label_for_field(
|
||||||
|
name=attribute_name, model=obj
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: Add others result types <=> Field types
|
# TODO: Add others result types <=> Field types
|
||||||
if isinstance(result, models.query.QuerySet):
|
if isinstance(result, models.query.QuerySet):
|
||||||
self.fields[extra_field['field']] = \
|
self.fields[field] = forms.ModelMultipleChoiceField(
|
||||||
forms.ModelMultipleChoiceField(
|
queryset=result, label=label
|
||||||
queryset=result, label=label)
|
)
|
||||||
else:
|
else:
|
||||||
self.fields[extra_field['field']] = forms.CharField(
|
self.fields[field] = forms.CharField(
|
||||||
label=extra_field['label'],
|
|
||||||
initial=resolve_attribute(
|
initial=resolve_attribute(
|
||||||
obj=self.instance,
|
obj=obj,
|
||||||
attribute=extra_field['field']
|
attribute=field
|
||||||
),
|
), label=label,
|
||||||
widget=extra_field.get('widget', PlainWidget)
|
widget=extra_field.get('widget', PlainWidget)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -131,7 +195,7 @@ class FileDisplayForm(forms.Form):
|
|||||||
self.fields['text'].initial = file_object.read()
|
self.fields['text'].initial = file_object.read()
|
||||||
|
|
||||||
|
|
||||||
class FilteredSelectionFormOptions(object):
|
class FilteredSelectionFormOptions(FormOptions):
|
||||||
# Dictionary list of option names and default values
|
# Dictionary list of option names and default values
|
||||||
option_definitions = (
|
option_definitions = (
|
||||||
{'allow_multiple': False},
|
{'allow_multiple': False},
|
||||||
@@ -147,35 +211,6 @@ class FilteredSelectionFormOptions(object):
|
|||||||
{'widget_attributes': {'size': '10'}},
|
{'widget_attributes': {'size': '10'}},
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, form, kwargs, options=None):
|
|
||||||
"""
|
|
||||||
Option definitions will be iterated. The option value will be
|
|
||||||
determined in the following order: as passed via keyword
|
|
||||||
arguments during form intialization, as form get_... method or
|
|
||||||
finally as static Meta options. This is to allow a form with
|
|
||||||
Meta options or method to be overrided at initialization
|
|
||||||
and increase the usability of a single class.
|
|
||||||
"""
|
|
||||||
for option_definition in self.option_definitions:
|
|
||||||
name = option_definition.keys()[0]
|
|
||||||
default_value = option_definition.values()[0]
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Check for a runtime value via kwargs
|
|
||||||
value = kwargs.pop(name)
|
|
||||||
except KeyError:
|
|
||||||
try:
|
|
||||||
# Check if there is a get_... method
|
|
||||||
value = getattr(self, 'get_{}'.format(name))()
|
|
||||||
except AttributeError:
|
|
||||||
try:
|
|
||||||
# Check the meta class options
|
|
||||||
value = getattr(options, name)
|
|
||||||
except AttributeError:
|
|
||||||
value = default_value
|
|
||||||
|
|
||||||
setattr(self, name, value)
|
|
||||||
|
|
||||||
|
|
||||||
class FilteredSelectionForm(forms.Form):
|
class FilteredSelectionForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import shutil
|
|||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.urls import resolve as django_resolve
|
from django.urls import resolve as django_resolve
|
||||||
from django.urls.base import get_script_prefix
|
from django.urls.base import get_script_prefix
|
||||||
@@ -142,6 +143,30 @@ def get_storage_subclass(dotted_path):
|
|||||||
return StorageSubclass
|
return StorageSubclass
|
||||||
|
|
||||||
|
|
||||||
|
def introspect_attribute(attribute_name, obj):
|
||||||
|
try:
|
||||||
|
# Try as a related field
|
||||||
|
obj._meta.get_field(field_name=attribute_name)
|
||||||
|
except (AttributeError, FieldDoesNotExist):
|
||||||
|
attribute_name = attribute_name.replace('__', '.')
|
||||||
|
|
||||||
|
try:
|
||||||
|
# If there are separators in the attribute name, traverse them
|
||||||
|
# to the final attribute
|
||||||
|
attribute_part, attribute_remaining = attribute_name.split(
|
||||||
|
'.', 1
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
return attribute_name, obj
|
||||||
|
else:
|
||||||
|
return introspect_attribute(
|
||||||
|
attribute_name=attribute_part,
|
||||||
|
obj=related_field.related_model,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return attribute_name, obj
|
||||||
|
|
||||||
|
|
||||||
def TemporaryFile(*args, **kwargs):
|
def TemporaryFile(*args, **kwargs):
|
||||||
kwargs.update({'dir': setting_temporary_directory.value})
|
kwargs.update({'dir': setting_temporary_directory.value})
|
||||||
return tempfile.TemporaryFile(*args, **kwargs)
|
return tempfile.TemporaryFile(*args, **kwargs)
|
||||||
|
|||||||
Reference in New Issue
Block a user