dynamicforms 0.76.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dynamicforms/__init__.py +8 -0
- dynamicforms/action.py +521 -0
- dynamicforms/apps.py +5 -0
- dynamicforms/fields.py +1570 -0
- dynamicforms/filters.py +44 -0
- dynamicforms/locale/en/LC_MESSAGES/django.po +67 -0
- dynamicforms/locale/en/LC_MESSAGES/djangojs.po +31 -0
- dynamicforms/locale/sl/LC_MESSAGES/django.po +71 -0
- dynamicforms/locale/sl/LC_MESSAGES/djangojs.po +36 -0
- dynamicforms/management/__init__.py +0 -0
- dynamicforms/management/commands/__init__.py +0 -0
- dynamicforms/management/commands/clean_dfpreuploaded_files.py +26 -0
- dynamicforms/migrations/__init__.py +0 -0
- dynamicforms/mixins/__init__.py +27 -0
- dynamicforms/mixins/action.py +14 -0
- dynamicforms/mixins/choice/__init__.py +94 -0
- dynamicforms/mixins/choice/allow_tags.py +79 -0
- dynamicforms/mixins/choice/null_choice.py +26 -0
- dynamicforms/mixins/choice/single_choice.py +21 -0
- dynamicforms/mixins/color_field.py +4 -0
- dynamicforms/mixins/conditional_visibility.py +193 -0
- dynamicforms/mixins/enable_copy.py +4 -0
- dynamicforms/mixins/field_render.py +209 -0
- dynamicforms/mixins/file_field.py +5 -0
- dynamicforms/mixins/help_text.py +46 -0
- dynamicforms/mixins/implicit_hidden.py +7 -0
- dynamicforms/mixins/implicit_natural_date.py +88 -0
- dynamicforms/mixins/null_value.py +15 -0
- dynamicforms/mixins/password_field.py +23 -0
- dynamicforms/mixins/related_field_ajax.py +142 -0
- dynamicforms/mixins/rtf_field.py +58 -0
- dynamicforms/models.py +5 -0
- dynamicforms/models_utils.py +33 -0
- dynamicforms/pagination.py +175 -0
- dynamicforms/preupload_files.py +42 -0
- dynamicforms/progress.py +71 -0
- dynamicforms/renderers.py +1 -0
- dynamicforms/routers.py +36 -0
- dynamicforms/serializers.py +486 -0
- dynamicforms/struct.py +40 -0
- dynamicforms/template_render/__init__.py +10 -0
- dynamicforms/template_render/layout.py +178 -0
- dynamicforms/template_render/mixins/__init__.py +0 -0
- dynamicforms/template_render/mixins/base.py +39 -0
- dynamicforms/template_render/mixins/field.py +74 -0
- dynamicforms/template_render/mixins/listserializer.py +100 -0
- dynamicforms/template_render/mixins/render_mode_enum.py +8 -0
- dynamicforms/template_render/mixins/serializer.py +301 -0
- dynamicforms/template_render/mixins/serializer_filter.py +19 -0
- dynamicforms/template_render/mixins/serializer_render_actions.py +21 -0
- dynamicforms/template_render/mixins/serializer_render_fields.py +57 -0
- dynamicforms/template_render/mixins/util.py +9 -0
- dynamicforms/template_render/renderer.py +38 -0
- dynamicforms/template_render/responsive_table_layout.py +64 -0
- dynamicforms/urls.py +9 -0
- dynamicforms/utils.py +32 -0
- dynamicforms/views.py +1 -0
- dynamicforms/viewsets.py +421 -0
- dynamicforms-0.76.14.dist-info/METADATA +129 -0
- dynamicforms-0.76.14.dist-info/RECORD +287 -0
- dynamicforms-0.76.14.dist-info/WHEEL +4 -0
- dynamicforms-0.76.14.dist-info/licenses/LICENSE +21 -0
- dynamicforms_legacy/__init__.py +8 -0
- dynamicforms_legacy/action.py +561 -0
- dynamicforms_legacy/apps.py +5 -0
- dynamicforms_legacy/context_processors.py +27 -0
- dynamicforms_legacy/dynamicforms_migration_mixin.py +42 -0
- dynamicforms_legacy/fields.py +1108 -0
- dynamicforms_legacy/filters.py +44 -0
- dynamicforms_legacy/migrations/__init__.py +0 -0
- dynamicforms_legacy/mixins/__init__.py +16 -0
- dynamicforms_legacy/mixins/action.py +14 -0
- dynamicforms_legacy/mixins/allow_tags.py +85 -0
- dynamicforms_legacy/mixins/enable_copy.py +4 -0
- dynamicforms_legacy/mixins/file_field.py +5 -0
- dynamicforms_legacy/mixins/help_text.py +38 -0
- dynamicforms_legacy/mixins/implicit_hidden.py +7 -0
- dynamicforms_legacy/mixins/implicit_natural_date.py +86 -0
- dynamicforms_legacy/mixins/null_choice.py +26 -0
- dynamicforms_legacy/mixins/null_value.py +15 -0
- dynamicforms_legacy/mixins/password_field.py +19 -0
- dynamicforms_legacy/mixins/related_field_ajax.py +58 -0
- dynamicforms_legacy/mixins/render.py +203 -0
- dynamicforms_legacy/mixins/rtf_field.py +52 -0
- dynamicforms_legacy/mixins/single_choice.py +21 -0
- dynamicforms_legacy/models.py +5 -0
- dynamicforms_legacy/pagination.py +168 -0
- dynamicforms_legacy/progress.py +71 -0
- dynamicforms_legacy/renderers.py +183 -0
- dynamicforms_legacy/serializers.py +335 -0
- dynamicforms_legacy/settings.py +196 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.css +587 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css +6 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.css +6834 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.min.css +6 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.eot +0 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.svg +288 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.ttf +0 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.woff +0 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/js/bootstrap.js +2580 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/js/bootstrap.min.js +6 -0
- dynamicforms_legacy/static/bootstrap-3.4.1-dist/js/npm.js +13 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.css +3719 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.min.css +7 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-grid.min.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.css +331 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.min.css +8 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap-reboot.min.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.css +10038 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.min.css +7 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/css/bootstrap.min.css.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.js +7013 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.js.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.min.js +7 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.bundle.min.js.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.js +4435 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.js.map +1 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.min.js +7 -0
- dynamicforms_legacy/static/bootstrap-4.3.1-dist/js/bootstrap.min.js.map +1 -0
- dynamicforms_legacy/static/ckeditor-df/ckEditorCustomBuildReadMe.txt +255 -0
- dynamicforms_legacy/static/ckeditor-df/ckeditor.js +6 -0
- dynamicforms_legacy/static/dynamicforms/dynamicforms.js +1883 -0
- dynamicforms_legacy/static/dynamicforms/icons/copy.svg +7 -0
- dynamicforms_legacy/static/dynamicforms/icons/eye-off-outline.svg +10 -0
- dynamicforms_legacy/static/dynamicforms/icons/eye-outline.svg +7 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_222222_256x240.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_228ef1_256x240.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_ef8c08_256x240.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_ffd27a_256x240.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/images/ui-icons_ffffff_256x240.png +0 -0
- dynamicforms_legacy/static/jquery_ui/css/jquery-ui.min.css +7 -0
- dynamicforms_legacy/static/jquery_ui/css/jquery-ui.structure.min.css +5 -0
- dynamicforms_legacy/static/jquery_ui/css/jquery-ui.theme.min.css +5 -0
- dynamicforms_legacy/static/jquery_ui/js/jquery-3.3.1.min.js +2 -0
- dynamicforms_legacy/static/jquery_ui/js/jquery-ui.min.js +13 -0
- dynamicforms_legacy/static/select2/css/select2-bootstrap3.min.css +7 -0
- dynamicforms_legacy/static/select2/css/select2-bootstrap4.min.css +578 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/css/select2.min.css +1 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/af.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ar.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/az.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/bg.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/bs.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ca.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/cs.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/da.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/de.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/dsb.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/el.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/en.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/es.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/et.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/eu.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/fa.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/fi.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/fr.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/gl.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/he.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hi.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hr.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hsb.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hu.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/hy.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/id.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/is.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/it.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ja.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/km.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ko.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/lt.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/lv.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/mk.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ms.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/nb.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/nl.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/pl.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ps.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/pt-BR.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/pt.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ro.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/ru.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sk.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sl.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sr-Cyrl.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sr.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/sv.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/th.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/tr.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/uk.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/vi.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/zh-CN.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/i18n/zh-TW.js +3 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.full.js +6457 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.full.min.js +1 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.js +5746 -0
- dynamicforms_legacy/static/select2/select2-4.0.5/js/select2.min.js +1 -0
- dynamicforms_legacy/struct.py +40 -0
- dynamicforms_legacy/templates/dynamicforms/base.html +12 -0
- dynamicforms_legacy/templates/dynamicforms/base_form.html +44 -0
- dynamicforms_legacy/templates/dynamicforms/base_includes.html +51 -0
- dynamicforms_legacy/templates/dynamicforms/base_includes_select2.html +6 -0
- dynamicforms_legacy/templates/dynamicforms/base_list.html +47 -0
- dynamicforms_legacy/templates/dynamicforms/base_table_body.html +46 -0
- dynamicforms_legacy/templates/dynamicforms/base_table_filter.html +44 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/base_form.html +10 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/base_includes.html +46 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/base_includes_v3.html +90 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/base_includes_v4.html +77 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/base_list.html +9 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/base_table_body.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/base_table_filter.html +5 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/base_field.html +41 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/base_field_v3.html +11 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/base_field_v4.html +11 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/checkbox.html +7 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/checkbox_multiple.html +7 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/fieldset.html +21 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/form.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/input.html +31 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/list_fieldset.html +18 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/radio.html +8 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/rtf_field.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/select.html +46 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/select_multiple.html +17 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/field/textarea.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/modal_dialog.html +13 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/modal_dialog_rest.html +23 -0
- dynamicforms_legacy/templates/dynamicforms/bootstrap/page.html +11 -0
- dynamicforms_legacy/templates/dynamicforms/field/base_field.html +55 -0
- dynamicforms_legacy/templates/dynamicforms/field/checkbox.html +28 -0
- dynamicforms_legacy/templates/dynamicforms/field/checkbox_multiple.html +16 -0
- dynamicforms_legacy/templates/dynamicforms/field/dict_field.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/field/fieldset.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/field/form.html +18 -0
- dynamicforms_legacy/templates/dynamicforms/field/input.html +31 -0
- dynamicforms_legacy/templates/dynamicforms/field/list_field.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/field/list_fieldset.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/field/radio.html +24 -0
- dynamicforms_legacy/templates/dynamicforms/field/rtf_field.html +14 -0
- dynamicforms_legacy/templates/dynamicforms/field/select.html +97 -0
- dynamicforms_legacy/templates/dynamicforms/field/select_multiple.html +67 -0
- dynamicforms_legacy/templates/dynamicforms/field/textarea.html +13 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_form.html +13 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_includes.html +225 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_list.html +9 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_table_body.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/base_table_filter.html +5 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/base_field.html +16 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/checkbox.html +7 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/checkbox_multiple.html +9 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/fieldset.html +11 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/form.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/input.html +17 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/list_fieldset.html +6 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/radio.html +8 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/rtf_field.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/select.html +37 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/select_multiple.html +18 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/field/textarea.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/modal_dialog.html +2 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/modal_dialog_rest.html +27 -0
- dynamicforms_legacy/templates/dynamicforms/jquery_ui/page.html +20 -0
- dynamicforms_legacy/templates/dynamicforms/modal_dialog.html +4 -0
- dynamicforms_legacy/templates/dynamicforms/modal_dialog_rest.html +18 -0
- dynamicforms_legacy/templates/dynamicforms/page.html +25 -0
- dynamicforms_legacy/templates/dynamicforms/rtf_field_style.html +41 -0
- dynamicforms_legacy/templatetags/__init__.py +0 -0
- dynamicforms_legacy/templatetags/dynamicforms.py +475 -0
- dynamicforms_legacy/urls.py +8 -0
- dynamicforms_legacy/views.py +1 -0
- dynamicforms_legacy/viewsets.py +366 -0
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
from collections import OrderedDict
|
|
2
|
+
from typing import Any, Dict, List
|
|
3
|
+
|
|
4
|
+
from django.core.exceptions import FieldDoesNotExist
|
|
5
|
+
from django.db import models
|
|
6
|
+
from django.db.models.fields.related import RelatedField
|
|
7
|
+
from rest_framework import serializers
|
|
8
|
+
from rest_framework.fields import get_attribute, SkipField
|
|
9
|
+
|
|
10
|
+
from dynamicforms.action import Actions
|
|
11
|
+
from dynamicforms.template_render import ViewModeSerializer
|
|
12
|
+
|
|
13
|
+
from . import fields
|
|
14
|
+
from .mixins import ActionMixin, DisplayMode, FieldRenderMixin
|
|
15
|
+
from .struct import StructDefault
|
|
16
|
+
from .utils import get_pk_name
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DynamicFormsSerializer(ViewModeSerializer, FieldRenderMixin, ActionMixin):
|
|
20
|
+
template_context = {} # see ViewSet.template_context
|
|
21
|
+
actions = Actions(add_default_crud=True, add_form_buttons=True)
|
|
22
|
+
form_titles = {
|
|
23
|
+
"table": "",
|
|
24
|
+
"new": "",
|
|
25
|
+
"edit": "",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
def __init__(self, *args, is_filter: bool = False, **kwds):
|
|
29
|
+
self.master = None
|
|
30
|
+
self.is_filter = is_filter
|
|
31
|
+
if self.is_filter:
|
|
32
|
+
try:
|
|
33
|
+
instance = self.Meta.model()
|
|
34
|
+
for fld in instance._meta.fields:
|
|
35
|
+
setattr(instance, fld.name, None)
|
|
36
|
+
except:
|
|
37
|
+
instance = StructDefault(_default_=None)
|
|
38
|
+
kwds.setdefault("instance", instance)
|
|
39
|
+
super().__init__(*args, **kwds)
|
|
40
|
+
if self.is_filter:
|
|
41
|
+
for field_name, field in self.fields.items():
|
|
42
|
+
field.default = None
|
|
43
|
+
field.allow_blank = True
|
|
44
|
+
field.allow_null = True
|
|
45
|
+
field.read_only = False
|
|
46
|
+
# the following ifs are actually redundant because front-end code currently doesn't even obey this
|
|
47
|
+
# it always renders the columns as visible in the table, except that in filter row, it takes
|
|
48
|
+
# the non-display fields for filtering instead of the resolved texts that can't be filtered
|
|
49
|
+
if (field_name + "-display") in self.fields.keys():
|
|
50
|
+
# if field has a resolved display counterpart (Choice, Related), show the original field
|
|
51
|
+
pass
|
|
52
|
+
elif field_name.endswith("-display"):
|
|
53
|
+
# if field is the resolved display counterpart, don't show it in filter row
|
|
54
|
+
pass
|
|
55
|
+
else:
|
|
56
|
+
field.display_form = field.display_table # filter's form is same as non-filter's table
|
|
57
|
+
field.allow_tags = False
|
|
58
|
+
field.password_field = False
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def has_non_field_errors(self):
|
|
62
|
+
"""
|
|
63
|
+
Reports whether validation turned up any form-wide validation errors. Used in templates to render the form-wide
|
|
64
|
+
error message
|
|
65
|
+
|
|
66
|
+
:return: True | False depending on whether form validation failed
|
|
67
|
+
"""
|
|
68
|
+
if hasattr(self, "_errors"):
|
|
69
|
+
return "non_field_errors" in self.errors
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def page_title(self):
|
|
74
|
+
"""
|
|
75
|
+
Returns page title from form_titles based on the rendered data
|
|
76
|
+
:return string: page title
|
|
77
|
+
"""
|
|
78
|
+
if self.render_type == "table":
|
|
79
|
+
return self.form_titles.get("table", "")
|
|
80
|
+
elif self.data.get("id", None):
|
|
81
|
+
return self.form_titles.get("edit", "")
|
|
82
|
+
else:
|
|
83
|
+
return self.form_titles.get("new", "")
|
|
84
|
+
|
|
85
|
+
# noinspection PyProtectedMember
|
|
86
|
+
@property
|
|
87
|
+
def filter_data(self):
|
|
88
|
+
"""
|
|
89
|
+
Returns serializer for filter row in table
|
|
90
|
+
:return: Serializer
|
|
91
|
+
"""
|
|
92
|
+
if self.view_mode == ViewModeSerializer.ViewMode.FORM:
|
|
93
|
+
return None
|
|
94
|
+
if getattr(self, "_filter_ser", None) is None:
|
|
95
|
+
# noinspection PyAttributeOutsideInit
|
|
96
|
+
self._filter_ser = type(self)(is_filter=True, context=getattr(self, "context", {}))
|
|
97
|
+
self._filter_ser.master = self
|
|
98
|
+
return self._filter_ser # Just create the same serializer in filter mode (None values, allow_nulls)
|
|
99
|
+
|
|
100
|
+
# noinspection PyUnusedLocal
|
|
101
|
+
def suppress_action(self, action, request, viewset):
|
|
102
|
+
"""
|
|
103
|
+
Determines whether rendering an action into the DOM should be suppressed. Use when some users don't have access
|
|
104
|
+
to some of the functionality, e.g. when CRUD functionality is only enabled for administrative users
|
|
105
|
+
:param action: action to be checked
|
|
106
|
+
:param request: request that triggered the render (may be None)
|
|
107
|
+
:param viewset: viewset that provided the serialized data (may be None)
|
|
108
|
+
:return: boolean whether action should render (False) or not (True)
|
|
109
|
+
"""
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def renderable_actions(self: "serializers.Serializer"):
|
|
114
|
+
"""
|
|
115
|
+
Returns those actions that are not suppressed
|
|
116
|
+
:return: List[Action]
|
|
117
|
+
"""
|
|
118
|
+
# TODO: Ta funkcija po mojem mora odletet (self.*controls*.actions). Sam zakaj ne? Ali se sploh ne uporablja?
|
|
119
|
+
request = self.context.get("request", None)
|
|
120
|
+
viewset = self.context.get("view", None)
|
|
121
|
+
return [action for action in self.controls.actions if not self.suppress_action(action, request, viewset)]
|
|
122
|
+
|
|
123
|
+
# noinspection PyUnresolvedReferences
|
|
124
|
+
def get_initial(self) -> Any:
|
|
125
|
+
if getattr(self, "_errors", None):
|
|
126
|
+
# This basically reproduces BaseSerializer.data property except that it disregards the _errors member
|
|
127
|
+
if self.instance:
|
|
128
|
+
res = self.to_representation(self.instance)
|
|
129
|
+
# elif hasattr(self, '_validated_data'):
|
|
130
|
+
# res = self.to_representation(self.validated_data)
|
|
131
|
+
else:
|
|
132
|
+
res = {}
|
|
133
|
+
res.update(super().get_initial())
|
|
134
|
+
|
|
135
|
+
return res
|
|
136
|
+
|
|
137
|
+
return super().get_initial()
|
|
138
|
+
|
|
139
|
+
# noinspection PyUnresolvedReferences
|
|
140
|
+
@property
|
|
141
|
+
def _writable_fields(self):
|
|
142
|
+
"""
|
|
143
|
+
Overrides DRF.serializers.Serializer._writable_fields
|
|
144
|
+
This one in particular should return exactly the same list as DRF's version (as of 17.4.2020, DRF version 3.11
|
|
145
|
+
"""
|
|
146
|
+
return (field for field in self.fields.values() if not field.read_only)
|
|
147
|
+
|
|
148
|
+
# noinspection PyUnresolvedReferences
|
|
149
|
+
@property
|
|
150
|
+
def _readable_fields(self):
|
|
151
|
+
"""
|
|
152
|
+
Overrides DRF.serializers.Serializer._readable_fields
|
|
153
|
+
This one adds additional checks on top of DRF's ones - checking if the field is renderable to table or form
|
|
154
|
+
"""
|
|
155
|
+
return (
|
|
156
|
+
field
|
|
157
|
+
for field in self.fields.values()
|
|
158
|
+
if not (
|
|
159
|
+
field.write_only
|
|
160
|
+
or (self.display_table == DisplayMode.SUPPRESS and self.display_form == DisplayMode.SUPPRESS)
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def to_representation(self, instance, row_data=None):
|
|
165
|
+
"""
|
|
166
|
+
Object instance -> Dict of primitive datatypes.
|
|
167
|
+
"""
|
|
168
|
+
ret = OrderedDict()
|
|
169
|
+
for field in self._readable_fields:
|
|
170
|
+
try:
|
|
171
|
+
attribute = field.get_attribute(instance)
|
|
172
|
+
if not isinstance(field, FieldRenderMixin):
|
|
173
|
+
ret[field.field_name] = field.to_representation(attribute)
|
|
174
|
+
else:
|
|
175
|
+
try:
|
|
176
|
+
ret[field.field_name] = field.to_representation(attribute, instance)
|
|
177
|
+
except:
|
|
178
|
+
if attribute is None and not field.required:
|
|
179
|
+
# DRF makes a special check for none and then always returns None if the check is None.
|
|
180
|
+
# We still want to process custom field to_representation, even if value is None.
|
|
181
|
+
# But when field is a sub-serializer and it (it's FK reference) is none, it's OK
|
|
182
|
+
# to pass None as result of serialization of such field
|
|
183
|
+
raise SkipField()
|
|
184
|
+
else:
|
|
185
|
+
raise
|
|
186
|
+
except SkipField:
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
return ret
|
|
190
|
+
|
|
191
|
+
# noinspection PyMethodMayBeStatic
|
|
192
|
+
def get_row_css_style(self, obj):
|
|
193
|
+
return ""
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class ModelSerializer(DynamicFormsSerializer, serializers.ModelSerializer):
|
|
197
|
+
"""
|
|
198
|
+
DynamicForms' ModelSerializer overrides the following behaviour over DRF's implementation:
|
|
199
|
+
|
|
200
|
+
* Uses own field types for construction
|
|
201
|
+
* Adds form UUID (rendered in html too)
|
|
202
|
+
* Adds processing for form-wide errors
|
|
203
|
+
|
|
204
|
+
DRF's docstring copied verbatim:
|
|
205
|
+
|
|
206
|
+
A `ModelSerializer` is just a regular `Serializer`, except that:
|
|
207
|
+
|
|
208
|
+
* A set of default fields are automatically populated.
|
|
209
|
+
* A set of default validators are automatically populated.
|
|
210
|
+
* Default `.create()` and `.update()` implementations are provided.
|
|
211
|
+
|
|
212
|
+
The process of automatically determining a set of serializer fields
|
|
213
|
+
based on the model fields is reasonably complex, but you almost certainly
|
|
214
|
+
don't need to dig into the implementation.
|
|
215
|
+
|
|
216
|
+
If the `ModelSerializer` class *doesn't* generate the set of fields that
|
|
217
|
+
you need you should either declare the extra/differing fields explicitly on
|
|
218
|
+
the serializer class, or simply use a `Serializer` class.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
def __init__(self, *args, is_filter: bool = False, **kwds):
|
|
222
|
+
if hasattr(self, "Meta") and hasattr(self.Meta, "fields"):
|
|
223
|
+
self._make_df_special_fields_present_in_fields(["df_prev_id", "row_css_style", "df_control_data"])
|
|
224
|
+
super().__init__(*args, is_filter=is_filter, **kwds)
|
|
225
|
+
self.manage_changed_flds()
|
|
226
|
+
self._decorate_fields()
|
|
227
|
+
|
|
228
|
+
def _decorate_fields(self):
|
|
229
|
+
def pop(self, name: str, default):
|
|
230
|
+
super(self.__class__, self).pop(name, default)
|
|
231
|
+
super(self.__class__, self).pop(name + "-display", None)
|
|
232
|
+
|
|
233
|
+
self.fields.pop = pop.__get__(self.fields)
|
|
234
|
+
# copy the labels to resolved -display fields
|
|
235
|
+
for field in self.fields:
|
|
236
|
+
if field.endswith("-display"):
|
|
237
|
+
self.fields[field].label = self.fields[field[:-8]].label
|
|
238
|
+
|
|
239
|
+
def _make_df_special_fields_present_in_fields(self, fields):
|
|
240
|
+
for f in fields:
|
|
241
|
+
if self.Meta.fields != "__all__" and f not in self.Meta.fields:
|
|
242
|
+
self.Meta.fields += (f,)
|
|
243
|
+
|
|
244
|
+
serializer_field_mapping = {
|
|
245
|
+
models.AutoField: fields.IntegerField,
|
|
246
|
+
models.BigIntegerField: fields.IntegerField,
|
|
247
|
+
models.BooleanField: fields.BooleanField,
|
|
248
|
+
models.NullBooleanField: fields.BooleanField,
|
|
249
|
+
models.CharField: fields.CharField,
|
|
250
|
+
models.CommaSeparatedIntegerField: fields.CharField,
|
|
251
|
+
models.DateField: fields.DateField,
|
|
252
|
+
models.DateTimeField: fields.DateTimeField,
|
|
253
|
+
models.DecimalField: fields.DecimalField,
|
|
254
|
+
models.EmailField: fields.EmailField,
|
|
255
|
+
models.Field: fields.ModelField,
|
|
256
|
+
models.FileField: fields.FileField,
|
|
257
|
+
models.FloatField: fields.FloatField,
|
|
258
|
+
models.ImageField: fields.ImageField,
|
|
259
|
+
models.IntegerField: fields.IntegerField,
|
|
260
|
+
models.PositiveIntegerField: fields.IntegerField,
|
|
261
|
+
models.PositiveSmallIntegerField: fields.IntegerField,
|
|
262
|
+
models.SlugField: fields.SlugField,
|
|
263
|
+
models.SmallIntegerField: fields.IntegerField,
|
|
264
|
+
models.TextField: fields.CharField,
|
|
265
|
+
models.TimeField: fields.TimeField,
|
|
266
|
+
models.URLField: fields.URLField,
|
|
267
|
+
models.GenericIPAddressField: fields.IPAddressField,
|
|
268
|
+
models.FilePathField: fields.FilePathField,
|
|
269
|
+
models.JSONField: fields.JSONField,
|
|
270
|
+
}
|
|
271
|
+
if models.DurationField is not None:
|
|
272
|
+
serializer_field_mapping[models.DurationField] = fields.DurationField
|
|
273
|
+
|
|
274
|
+
serializer_related_field = fields.PrimaryKeyRelatedField
|
|
275
|
+
serializer_related_to_field = fields.SlugRelatedField
|
|
276
|
+
serializer_url_field = fields.HyperlinkedIdentityField
|
|
277
|
+
serializer_choice_field = fields.ChoiceField
|
|
278
|
+
|
|
279
|
+
def get_field_names(self, declared_fields, info):
|
|
280
|
+
# we're just converting DRF's tuple to list here because we need it modifiable in get_uniqueness_extra_kwargs
|
|
281
|
+
return list(super().get_field_names(declared_fields, info))
|
|
282
|
+
|
|
283
|
+
def get_extra_kwargs(self):
|
|
284
|
+
res = super().get_extra_kwargs()
|
|
285
|
+
# noinspection PyUnresolvedReferences
|
|
286
|
+
for fld in self.Meta.model._meta.fields:
|
|
287
|
+
# We're exploiting DRF design "feature" here where DRF only perceives a field as declared if it's a Field
|
|
288
|
+
# instance. AutoGeneratedField is not a Field instance and will thus be overwritten by auto generated field
|
|
289
|
+
# Note how Field instances are already removed from the class here.
|
|
290
|
+
# They reappear in the get_uniqueness_extra_kwargs method below
|
|
291
|
+
fld_name = fld.db_column or fld.name
|
|
292
|
+
value = getattr(self, fld_name, None)
|
|
293
|
+
if isinstance(value, fields.AutoGeneratedField):
|
|
294
|
+
res.setdefault(fld_name, {})
|
|
295
|
+
res[fld_name].update(value)
|
|
296
|
+
return res
|
|
297
|
+
|
|
298
|
+
def get_uniqueness_extra_kwargs(self, field_names: List[str], declared_fields: Dict, extra_kwargs: Dict):
|
|
299
|
+
"""
|
|
300
|
+
Finds all ChoiceFields and RelatedFields and creates additional "-display" fields to show
|
|
301
|
+
resolved display value in table
|
|
302
|
+
"""
|
|
303
|
+
for field_name in field_names[:]:
|
|
304
|
+
# serializer field: either what is declared as a Field instance in Serializer or AutogeneratedField
|
|
305
|
+
s_field = declared_fields.get(field_name, getattr(self, field_name, None))
|
|
306
|
+
# existing extra as provided by get_extra_kwargs
|
|
307
|
+
extra = extra_kwargs.get(field_name, dict())
|
|
308
|
+
# model field, if it exists
|
|
309
|
+
try:
|
|
310
|
+
d_field = self.Meta.model._meta.get_field(field_name)
|
|
311
|
+
except FieldDoesNotExist:
|
|
312
|
+
d_field = None
|
|
313
|
+
|
|
314
|
+
if d_field and d_field.name == get_pk_name(self.Meta.model):
|
|
315
|
+
# hide the primary key field (DRF only marks it as R/O)
|
|
316
|
+
field_name = get_pk_name(self.Meta.model)
|
|
317
|
+
if field_name not in declared_fields and "display" not in extra:
|
|
318
|
+
extra.setdefault("display_form", fields.DisplayMode.HIDDEN)
|
|
319
|
+
extra.setdefault("display_table", fields.DisplayMode.FULL)
|
|
320
|
+
extra_kwargs[field_name] = extra
|
|
321
|
+
|
|
322
|
+
if isinstance(s_field, (fields.ChoiceMixin, fields.RelatedFieldAJAXMixin)) or (
|
|
323
|
+
# if custom field properties are declared and they are either ChoiceField or RelatedField
|
|
324
|
+
isinstance(d_field, RelatedField) # DB field is a relation
|
|
325
|
+
or getattr(d_field, "choices", None) # DB field has choices
|
|
326
|
+
):
|
|
327
|
+
if (s_field and getattr(s_field, "display_table", DisplayMode.SUPPRESS) == DisplayMode.SUPPRESS) or (
|
|
328
|
+
hasattr(self, "Meta") and hasattr(self.Meta, "exclude") and field_name in self.Meta.exclude
|
|
329
|
+
):
|
|
330
|
+
# if the field is set to not display in the table, don't create the resolved field
|
|
331
|
+
continue
|
|
332
|
+
|
|
333
|
+
# original field does not display in the table
|
|
334
|
+
if field_name in declared_fields:
|
|
335
|
+
# declared fields cannot also have extra_kwargs (there is a continue in the loop)
|
|
336
|
+
s_field.display_table = DisplayMode.HIDDEN
|
|
337
|
+
else:
|
|
338
|
+
extra["display_table"] = DisplayMode.HIDDEN
|
|
339
|
+
extra_kwargs[field_name] = extra
|
|
340
|
+
|
|
341
|
+
resolved_field_name = f"{field_name}-display"
|
|
342
|
+
# if resolved_field_name in declared_fields or resolved_field_name in extra_kwargs:
|
|
343
|
+
# raise ValueError(f"We were going to add a table resolved field '{resolved_field_name}' but "
|
|
344
|
+
# f"a field with this name is already declared in "
|
|
345
|
+
# f"the serializer {self.__class__.__name__")
|
|
346
|
+
field_names.insert(field_names.index(field_name) + 1, resolved_field_name)
|
|
347
|
+
declared_fields[resolved_field_name] = fields.SerializerMethodField(
|
|
348
|
+
source="*",
|
|
349
|
+
display_form=DisplayMode.HIDDEN,
|
|
350
|
+
display_table=DisplayMode.FULL,
|
|
351
|
+
render_params=s_field.render_params if s_field else None,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
def get_resolve_method(fld_nm, res_fld):
|
|
355
|
+
def resolve_choice_field(self, value):
|
|
356
|
+
from dynamicforms.fields import ManyRelatedField
|
|
357
|
+
|
|
358
|
+
if (
|
|
359
|
+
isinstance(self.fields[fld_nm], ManyRelatedField)
|
|
360
|
+
and value
|
|
361
|
+
and not getattr(value, "pk", None)
|
|
362
|
+
):
|
|
363
|
+
return None
|
|
364
|
+
|
|
365
|
+
source_attr = self.fields[fld_nm].source_attrs
|
|
366
|
+
row_data = value
|
|
367
|
+
try:
|
|
368
|
+
value = get_attribute(value, source_attr)
|
|
369
|
+
except:
|
|
370
|
+
value = None
|
|
371
|
+
|
|
372
|
+
return self.fields[fld_nm].render_to_table(
|
|
373
|
+
# getattr has a default == None because the object might be a new init and
|
|
374
|
+
# will not have relations
|
|
375
|
+
value,
|
|
376
|
+
row_data,
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
return resolve_choice_field
|
|
380
|
+
|
|
381
|
+
setattr(
|
|
382
|
+
self,
|
|
383
|
+
f"get_{resolved_field_name}",
|
|
384
|
+
get_resolve_method(field_name, resolved_field_name).__get__(self),
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
if hasattr(self, "Meta") and hasattr(self.Meta, "fields"):
|
|
388
|
+
if isinstance(self.Meta.fields, tuple):
|
|
389
|
+
self.Meta.fields = list(self.Meta.fields)
|
|
390
|
+
self.Meta.fields.append(resolved_field_name)
|
|
391
|
+
|
|
392
|
+
# print(
|
|
393
|
+
# f"We will be creating a resolved field for field {field_name}. "
|
|
394
|
+
# f"Field is already custom-declared: {bool(s_field)}"
|
|
395
|
+
# )
|
|
396
|
+
pass
|
|
397
|
+
|
|
398
|
+
return super().get_uniqueness_extra_kwargs(field_names, declared_fields, extra_kwargs)
|
|
399
|
+
|
|
400
|
+
# noinspection PyUnresolvedReferences
|
|
401
|
+
def manage_changed_flds(self):
|
|
402
|
+
"""
|
|
403
|
+
When there is a need to only change few parameters of a field put those fields and changed parameters in
|
|
404
|
+
serializers Meta class in parameter changed_flds.
|
|
405
|
+
|
|
406
|
+
Example:
|
|
407
|
+
|
|
408
|
+
.. code-block:: python
|
|
409
|
+
|
|
410
|
+
changed_flds = {
|
|
411
|
+
'id': dict(display=DisplayMode.HIDDEN),
|
|
412
|
+
'comment': dict(label='Comm', help_text='Help text for comment field')
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
:return:
|
|
416
|
+
|
|
417
|
+
"""
|
|
418
|
+
if hasattr(self.Meta, "changed_flds"):
|
|
419
|
+
import warnings
|
|
420
|
+
|
|
421
|
+
warnings.warn(
|
|
422
|
+
f"""
|
|
423
|
+
{self.__class__.__module__}.{self.__class__.__name__}:
|
|
424
|
+
changed_flds has been found to be a duplicate of DRF's extra_kwargs Meta member. Either use
|
|
425
|
+
extra_kwargs or the preferred field = AutoGeneratedField(**kwargs) declaration.
|
|
426
|
+
""",
|
|
427
|
+
DeprecationWarning,
|
|
428
|
+
stacklevel=6,
|
|
429
|
+
)
|
|
430
|
+
for field, params in self.Meta.changed_flds.items():
|
|
431
|
+
field_def = self.fields.get(field, None)
|
|
432
|
+
if field_def:
|
|
433
|
+
for key, val in params.items():
|
|
434
|
+
setattr(field_def, key, val)
|
|
435
|
+
|
|
436
|
+
# Dynamic forms default field that is used to contain data for positioning (id of previous record)
|
|
437
|
+
df_prev_id = fields.SerializerMethodField(display=DisplayMode.HIDDEN)
|
|
438
|
+
|
|
439
|
+
# this is a calculated field that returns css style for table row
|
|
440
|
+
row_css_style = fields.SerializerMethodField(display=DisplayMode.HIDDEN)
|
|
441
|
+
|
|
442
|
+
def fetch_prev_id(self, obj, view):
|
|
443
|
+
ordering = "id"
|
|
444
|
+
try:
|
|
445
|
+
ordering = view.pagination_class.ordering
|
|
446
|
+
except:
|
|
447
|
+
pass
|
|
448
|
+
if ordering != "id":
|
|
449
|
+
query_params = self.context["request"].query_params
|
|
450
|
+
query_params._mutable = True
|
|
451
|
+
query_params.pop("id", "")
|
|
452
|
+
queryset = view.filter_queryset(queryset=view.get_queryset(), query_params=query_params)
|
|
453
|
+
records = list(queryset.order_by(ordering))
|
|
454
|
+
curr_index = records.index(obj)
|
|
455
|
+
prev_id = None
|
|
456
|
+
if curr_index > 0:
|
|
457
|
+
prev_id = records[curr_index - 1].id
|
|
458
|
+
|
|
459
|
+
return prev_id
|
|
460
|
+
|
|
461
|
+
return ""
|
|
462
|
+
|
|
463
|
+
# noinspection PyMethodMayBeStatic
|
|
464
|
+
def get_df_prev_id(self, obj):
|
|
465
|
+
try:
|
|
466
|
+
if self.context["request"].META.get("HTTP_X_DF_CALLTYPE", "") == "refresh_record":
|
|
467
|
+
view = self.context.get("view", None)
|
|
468
|
+
if view:
|
|
469
|
+
return self.fetch_prev_id(obj, view)
|
|
470
|
+
except:
|
|
471
|
+
pass
|
|
472
|
+
|
|
473
|
+
return ""
|
|
474
|
+
|
|
475
|
+
def render_to_table(self, value, row_data):
|
|
476
|
+
return str(value) if value is not None else None
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class Serializer(DynamicFormsSerializer, serializers.Serializer):
|
|
480
|
+
def update(self, instance, validated_data):
|
|
481
|
+
# Implemented just so IDE doesn't complain. Normally this will be handled in SingleRecordViewSet
|
|
482
|
+
pass
|
|
483
|
+
|
|
484
|
+
def create(self, validated_data):
|
|
485
|
+
# Implemented just so IDE doesn't complain. Normally this will be handled in SingleRecordViewSet
|
|
486
|
+
pass
|
dynamicforms/struct.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
class Struct(object):
|
|
2
|
+
def __init__(self, data=None, **kwds):
|
|
3
|
+
if not data:
|
|
4
|
+
data = {}
|
|
5
|
+
for name, value in data.items():
|
|
6
|
+
if name:
|
|
7
|
+
setattr(self, name, self._wrap(value))
|
|
8
|
+
for name, value in kwds.items():
|
|
9
|
+
if name:
|
|
10
|
+
setattr(self, name, self._wrap(value))
|
|
11
|
+
|
|
12
|
+
def _wrap(self, value):
|
|
13
|
+
if isinstance(value, (tuple, list, set, frozenset)):
|
|
14
|
+
return type(value)([self._wrap(v) for v in value])
|
|
15
|
+
else:
|
|
16
|
+
return Struct(value) if isinstance(value, dict) else value
|
|
17
|
+
|
|
18
|
+
def clone(self, **kwds):
|
|
19
|
+
return Struct(self.__to_dict__(), **kwds)
|
|
20
|
+
|
|
21
|
+
def __repr__(self):
|
|
22
|
+
return "Struct: " + repr(self.__dict__)
|
|
23
|
+
|
|
24
|
+
def __len__(self):
|
|
25
|
+
return len(self.__dict__)
|
|
26
|
+
|
|
27
|
+
def __to_dict__(self):
|
|
28
|
+
res = {}
|
|
29
|
+
res.update(self.__dict__)
|
|
30
|
+
for k in res.keys():
|
|
31
|
+
if isinstance(res[k], Struct):
|
|
32
|
+
res[k] = res[k].__to_dict__()
|
|
33
|
+
elif isinstance(res[k], (tuple, list, set, frozenset)):
|
|
34
|
+
res[k] = [i.__to_dict__() if isinstance(i, Struct) else i for i in res[k]]
|
|
35
|
+
return res
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class StructDefault(Struct):
|
|
39
|
+
def __getattr__(self, item):
|
|
40
|
+
return self._default_
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
What DynamicForms is about: ability to render a Serializer directly in Django template --> HTML
|
|
3
|
+
This module allows for it. It defines __str__ method on Serializer, ListSerializer and Field instances to render to HTML
|
|
4
|
+
"""
|
|
5
|
+
from .mixins.field import ViewModeField
|
|
6
|
+
from .mixins.listserializer import ViewModeListSerializer
|
|
7
|
+
from .mixins.serializer import ViewModeSerializer
|
|
8
|
+
from .renderer import ComponentDefRenderer
|
|
9
|
+
|
|
10
|
+
__all__ = (ViewModeField, ViewModeSerializer, ViewModeListSerializer, ComponentDefRenderer)
|