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,366 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
from typing import List, Union
|
|
3
|
+
|
|
4
|
+
import pytz
|
|
5
|
+
|
|
6
|
+
from django.conf import settings
|
|
7
|
+
from django.contrib.auth.views import redirect_to_login
|
|
8
|
+
from django.db import models
|
|
9
|
+
from django.http import Http404
|
|
10
|
+
from rest_framework import status, viewsets
|
|
11
|
+
from rest_framework.exceptions import ValidationError
|
|
12
|
+
from rest_framework.renderers import JSONRenderer
|
|
13
|
+
from rest_framework.response import Response
|
|
14
|
+
from rest_framework.serializers import ListSerializer
|
|
15
|
+
from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList
|
|
16
|
+
|
|
17
|
+
from dynamicforms_legacy.fields import BooleanField
|
|
18
|
+
|
|
19
|
+
from .renderers import TemplateHTMLRenderer
|
|
20
|
+
from .settings import DYNAMICFORMS
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class NewMixin(object):
|
|
24
|
+
"""
|
|
25
|
+
Provides support for retrieving default values for a new record.
|
|
26
|
+
|
|
27
|
+
Caution: Do not use directly. This is only a mixin and is used in final ViewSet derivatives.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def new_object(self: viewsets.ModelViewSet):
|
|
31
|
+
"""
|
|
32
|
+
Returns a new model instance. If you need it pre-populated with default values, this is the method to override.
|
|
33
|
+
|
|
34
|
+
:return: model instance
|
|
35
|
+
"""
|
|
36
|
+
# TODO: This function must return an object that has its field values correctly / realistically filled out
|
|
37
|
+
# Example: if a certain field's value hides (sets another field to None), then that second field can't be
|
|
38
|
+
# set to 42, can it?
|
|
39
|
+
# can we run some kind of validation to enforce this?
|
|
40
|
+
# Not that easy: the returned record may not validate for its (correctly) empty fields
|
|
41
|
+
# Maybe we will have to run JavaScript onchange for all fields displayed to ensure at least some consistency?
|
|
42
|
+
# If we do not, subsequent validation may fail because a hidden field has a value
|
|
43
|
+
field_names = [
|
|
44
|
+
(f.name + "_id") if isinstance(f, models.ForeignKey) else f.name
|
|
45
|
+
for f in self.get_queryset().model._meta.fields
|
|
46
|
+
]
|
|
47
|
+
instantiation_params = {k: v for k, v in self.request.GET.items() if k in field_names}
|
|
48
|
+
return self.get_queryset().model(**instantiation_params)
|
|
49
|
+
|
|
50
|
+
# noinspection PyUnresolvedReferences
|
|
51
|
+
def retrieve(self: viewsets.ModelViewSet, request, *args, **kwargs):
|
|
52
|
+
try:
|
|
53
|
+
if not hasattr(super(), "retrieve"):
|
|
54
|
+
raise Http404() # This is not a ModelViewSet, so we don't have a retrieval mechanism
|
|
55
|
+
return super().retrieve(request, *args, **kwargs)
|
|
56
|
+
except Http404:
|
|
57
|
+
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
|
|
58
|
+
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
|
|
59
|
+
if filter_kwargs.get("pk", None) == "new":
|
|
60
|
+
instance = self.new_object()
|
|
61
|
+
serializer = self.get_serializer(instance)
|
|
62
|
+
return Response(serializer.data)
|
|
63
|
+
else:
|
|
64
|
+
raise
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PutPostMixin(object):
|
|
68
|
+
"""
|
|
69
|
+
Provides support for when there is no record id in URL when calling PUT
|
|
70
|
+
(First empty form is loaded. Than user loads existing data to this form and updates it... - Perform PUT action)
|
|
71
|
+
|
|
72
|
+
or
|
|
73
|
+
|
|
74
|
+
Provides support for when there is record id in URL when calling POST
|
|
75
|
+
(First form for some existing record is loaded. Than user wants to create new record for it.
|
|
76
|
+
- deletes redord ID and perform POST action)
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
# When there is no record id in URL when calling PUT, this function will be called
|
|
80
|
+
# noinspection PyUnresolvedReferences
|
|
81
|
+
def put(self: viewsets.ModelViewSet, request, *args, **kwargs):
|
|
82
|
+
self.kwargs["pk"] = request.data["id"]
|
|
83
|
+
return self.update(request, *args, **kwargs)
|
|
84
|
+
|
|
85
|
+
# When there is record id in URL when calling POST, this function will be called
|
|
86
|
+
# noinspection PyUnresolvedReferences
|
|
87
|
+
def post(self: viewsets.ModelViewSet, request, *args, **kwargs):
|
|
88
|
+
return self.create(request, *args, **kwargs)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class TemplateRendererMixin:
|
|
92
|
+
template_context = {}
|
|
93
|
+
"""
|
|
94
|
+
template_context provides configuration to templates being rendered
|
|
95
|
+
|
|
96
|
+
Note that when adding data from database, it is advised to make this definition a callable so that it is evaluated
|
|
97
|
+
on each render of the ViewSet: that way you can ensure data is always loaded fresh from database.
|
|
98
|
+
This member can also be defined in the serializer class. If that is the case, it will be copied to ViewSet.
|
|
99
|
+
|
|
100
|
+
e.g.
|
|
101
|
+
|
|
102
|
+
.. code-block:: python
|
|
103
|
+
|
|
104
|
+
template_context = lambda self: dict(items=MyModel.objects.all())
|
|
105
|
+
|
|
106
|
+
or
|
|
107
|
+
|
|
108
|
+
.. code-block:: python
|
|
109
|
+
|
|
110
|
+
def template_context(self):
|
|
111
|
+
return dict(items=MyModel.objects.all())
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
template_name = DYNAMICFORMS.table_base_template #: template filename for listing multiple records (html renderer)
|
|
115
|
+
|
|
116
|
+
def __init__(self, *args, **kwds):
|
|
117
|
+
if not self.template_context and getattr(self, "serializer_class", None) is not None:
|
|
118
|
+
self.template_context = getattr(self.serializer_class, "template_context", {})
|
|
119
|
+
super().__init__(*args, **kwds)
|
|
120
|
+
|
|
121
|
+
# noinspection PyAttributeOutsideInit
|
|
122
|
+
def initialize_request(self, request, *args, **kwargs):
|
|
123
|
+
# Caution: just to be sure for any future debugging: the request parameter to this function is a WSGIRequest
|
|
124
|
+
# while the return Request is actually DRF Request
|
|
125
|
+
# As a consequence, form values don't get parsed until you actually call super().initialize_request
|
|
126
|
+
# There's no "request.data", etc. Just saying. So you don't debug for two hours next time. By "you" I mean me
|
|
127
|
+
|
|
128
|
+
# Force render using a given render path (full page, table, table rows, form, dialog with form)
|
|
129
|
+
self.render_type = request.META.get("HTTP_X_DF_RENDER_TYPE", request.GET.get("df_render_type", "page"))
|
|
130
|
+
|
|
131
|
+
if request.method.lower() == "post" and request.POST.get("data-dynamicforms-method", None):
|
|
132
|
+
# This is a hack because HTML forms can only do POST & GET. This way we also get PUT & PATCH
|
|
133
|
+
request.method = request.POST.get("data-dynamicforms-method")
|
|
134
|
+
# If we don't set this META, django won't recognise our CSRF token
|
|
135
|
+
request.META["HTTP_X_CSRFTOKEN"] = request.POST["csrfmiddlewaretoken"]
|
|
136
|
+
return super().initialize_request(request, *args, **kwargs)
|
|
137
|
+
|
|
138
|
+
def finalize_response(self, request, response, *args, **kwargs):
|
|
139
|
+
if not isinstance(response, Response):
|
|
140
|
+
return response
|
|
141
|
+
|
|
142
|
+
res = super().finalize_response(request, response, *args, **kwargs)
|
|
143
|
+
|
|
144
|
+
def get_query_params():
|
|
145
|
+
if request.query_params:
|
|
146
|
+
return "?" + "&".join(["%s=%s" % (key, value) for key, value in request.query_params.items()])
|
|
147
|
+
return ""
|
|
148
|
+
|
|
149
|
+
if isinstance(res.accepted_renderer, TemplateHTMLRenderer):
|
|
150
|
+
if status.is_success(res.status_code) or res.status_code == status.HTTP_400_BAD_REQUEST:
|
|
151
|
+
if (
|
|
152
|
+
isinstance(res.data, dict)
|
|
153
|
+
and "next" in res.data
|
|
154
|
+
and "results" in res.data
|
|
155
|
+
and isinstance(res.data["results"], (ReturnList, ReturnDict))
|
|
156
|
+
):
|
|
157
|
+
serializer = res.data["results"].serializer
|
|
158
|
+
else:
|
|
159
|
+
try:
|
|
160
|
+
serializer = res.data.serializer
|
|
161
|
+
except AttributeError:
|
|
162
|
+
# This happens when there's a ValidationError on LIST command
|
|
163
|
+
res.accepted_renderer = JSONRenderer()
|
|
164
|
+
return res
|
|
165
|
+
|
|
166
|
+
if isinstance(serializer, ListSerializer):
|
|
167
|
+
serializer.child.render_type = self.render_type
|
|
168
|
+
else:
|
|
169
|
+
serializer.render_type = self.render_type
|
|
170
|
+
|
|
171
|
+
if self.render_type in ("table", "table rows"):
|
|
172
|
+
serializer.data_template = self.template_name
|
|
173
|
+
elif self.render_type == "dialog":
|
|
174
|
+
serializer.data_template = DYNAMICFORMS.modal_dialog_rest_template
|
|
175
|
+
res.template_name = DYNAMICFORMS.modal_dialog_rest_template
|
|
176
|
+
elif self.render_type == "form":
|
|
177
|
+
serializer.data_template = res.data.serializer.template_name
|
|
178
|
+
res.template_name = res.data.serializer.template_name
|
|
179
|
+
else:
|
|
180
|
+
if isinstance(serializer, ListSerializer):
|
|
181
|
+
serializer.child.render_type = "table"
|
|
182
|
+
serializer.child.data_template = self.template_name
|
|
183
|
+
else:
|
|
184
|
+
serializer.render_type = "form"
|
|
185
|
+
serializer.data_template = serializer.template_name
|
|
186
|
+
elif (
|
|
187
|
+
res.status_code in (status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN)
|
|
188
|
+
and self.render_type != "dialog"
|
|
189
|
+
):
|
|
190
|
+
# TODO: We should show a message here that user is not authorized for this action (only for 403)
|
|
191
|
+
if not request.is_ajax():
|
|
192
|
+
res = redirect_to_login(request.path_info + get_query_params())
|
|
193
|
+
return res
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class ModelViewSet(NewMixin, PutPostMixin, TemplateRendererMixin, viewsets.ModelViewSet):
|
|
197
|
+
"""
|
|
198
|
+
In addition to all the functionality, provided by DRF, DynamicForms ViewSet has some extra features:
|
|
199
|
+
|
|
200
|
+
* Separate templates for rendering list or single record
|
|
201
|
+
* You can request a "new" record and even have it pre-populated with values
|
|
202
|
+
* To render viewset as API or JSON use the same method as in DRF: To render it in HTML just add ".html" to the URL.
|
|
203
|
+
* Standard DRF router URL patterns apply:
|
|
204
|
+
|
|
205
|
+
* To render a new record use pk=new.
|
|
206
|
+
* To render an existing record (for editing) use pk={record_id}.
|
|
207
|
+
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
def paginate_queryset(self, queryset):
|
|
211
|
+
"""
|
|
212
|
+
Return a single page of results, or `None` if pagination is disabled.
|
|
213
|
+
"""
|
|
214
|
+
if self.paginator is None:
|
|
215
|
+
return None
|
|
216
|
+
# determine request format and handle pagination for json format
|
|
217
|
+
if isinstance(self.request.accepted_renderer, JSONRenderer) and not BooleanField().to_internal_value(
|
|
218
|
+
self.request.META.get("HTTP_X_PAGINATION", self.request.GET.get("x_df_pagination", False))
|
|
219
|
+
):
|
|
220
|
+
return None
|
|
221
|
+
return self.paginator.paginate_queryset(queryset, self.request, view=self)
|
|
222
|
+
|
|
223
|
+
def get_queryset(self):
|
|
224
|
+
"""
|
|
225
|
+
Returns records from queryset with filters applied
|
|
226
|
+
|
|
227
|
+
:return: filtered records
|
|
228
|
+
"""
|
|
229
|
+
return super().get_queryset()
|
|
230
|
+
|
|
231
|
+
def filter_queryset(self, queryset, query_params=None):
|
|
232
|
+
"""
|
|
233
|
+
Applies filters for all fields
|
|
234
|
+
|
|
235
|
+
:param queryset: Queryset
|
|
236
|
+
:param query_params: Custom query_params if needed
|
|
237
|
+
:return: queryset with filters applied
|
|
238
|
+
"""
|
|
239
|
+
res = super().filter_queryset(queryset)
|
|
240
|
+
if self.request:
|
|
241
|
+
if query_params is None:
|
|
242
|
+
query_params = self.request.query_params
|
|
243
|
+
for fld, val in query_params.items():
|
|
244
|
+
res = self.filter_queryset_field(res, fld, val)
|
|
245
|
+
for backend in self.filter_backends:
|
|
246
|
+
if hasattr(backend, "get_ordering"):
|
|
247
|
+
ordering = backend().get_ordering(self.request, queryset, self)
|
|
248
|
+
if ordering:
|
|
249
|
+
self.ordering = ordering
|
|
250
|
+
break
|
|
251
|
+
return res
|
|
252
|
+
|
|
253
|
+
# noinspection PyMethodMayBeStatic
|
|
254
|
+
def filter_queryset_field(self, queryset, field, value):
|
|
255
|
+
"""
|
|
256
|
+
Applies filter to individual field
|
|
257
|
+
|
|
258
|
+
:param queryset: Queryset
|
|
259
|
+
:param field: Field name
|
|
260
|
+
:param value: Field value
|
|
261
|
+
:return: queryset with applied filter for the field
|
|
262
|
+
"""
|
|
263
|
+
if value is None or value == "":
|
|
264
|
+
return queryset
|
|
265
|
+
|
|
266
|
+
model_meta = queryset.model._meta
|
|
267
|
+
|
|
268
|
+
if field not in (fld.name for fld in model_meta.get_fields()):
|
|
269
|
+
return queryset
|
|
270
|
+
|
|
271
|
+
# TODO: this would probably be better moved into the fields themselves
|
|
272
|
+
if isinstance(model_meta.get_field(field), (models.CharField, models.TextField)):
|
|
273
|
+
return queryset.filter(**{field + "__icontains": value})
|
|
274
|
+
if isinstance(model_meta.get_field(field), (models.DateField, models.DateTimeField)):
|
|
275
|
+
date_time = None
|
|
276
|
+
for date_time_fmt in [settings.DATETIME_FORMAT, "%Y-%m-%dT%H:%M:%S", settings.DATE_FORMAT, "%Y-%m-%d"]:
|
|
277
|
+
try:
|
|
278
|
+
date_time = datetime.strptime(value, date_time_fmt)
|
|
279
|
+
break
|
|
280
|
+
except:
|
|
281
|
+
pass
|
|
282
|
+
if date_time is None:
|
|
283
|
+
return queryset
|
|
284
|
+
date_time = pytz.timezone(settings.TIME_ZONE).localize(date_time).astimezone(pytz.utc)
|
|
285
|
+
if len(value) <= 10:
|
|
286
|
+
return queryset.filter(**{field + "__gte": date_time, field + "__lt": date_time + timedelta(days=1)})
|
|
287
|
+
return queryset.filter(**{field + "__gte": date_time, field + "__lt": date_time + timedelta(seconds=1)})
|
|
288
|
+
else:
|
|
289
|
+
if isinstance(model_meta.get_field(field), models.BooleanField):
|
|
290
|
+
value = value == "true"
|
|
291
|
+
return queryset.filter(**{field: value})
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
def generate_paged_loader(page_size: int = 30, ordering: Union[str, List[str]] = "id"):
|
|
295
|
+
"""
|
|
296
|
+
Generates a Pagination class that will handle dynamic data loading for ViewSets with a lot of data.
|
|
297
|
+
Use by declaring `pagination_class = ModelViewSet.generate_paged_loader()` in class variables
|
|
298
|
+
|
|
299
|
+
:param page_size: how many records should be fetched at a time
|
|
300
|
+
:param ordering: This should be a string, or list of strings, indicating the field against which the cursor
|
|
301
|
+
based pagination will be applied. For example: ordering = 'slug'
|
|
302
|
+
:return: a Pagination class
|
|
303
|
+
"""
|
|
304
|
+
from dynamicforms_legacy.pagination import CursorPagination
|
|
305
|
+
|
|
306
|
+
ps = page_size
|
|
307
|
+
ordr = ordering
|
|
308
|
+
|
|
309
|
+
class MyCursorPagination(CursorPagination):
|
|
310
|
+
ordering = ordr
|
|
311
|
+
page_size = ps
|
|
312
|
+
df_request = None
|
|
313
|
+
|
|
314
|
+
def paginate_queryset(self, queryset, request, view=None):
|
|
315
|
+
self.df_request = request
|
|
316
|
+
return super().paginate_queryset(queryset, request, view)
|
|
317
|
+
|
|
318
|
+
def encode_cursor(self, cursor):
|
|
319
|
+
# Following code is needed when we have https proxy server that redirects requests to http servers.
|
|
320
|
+
# In that case original code generates cursor links that have http scheme.
|
|
321
|
+
# So here I check REFERER header to find out which scheme is originally declared.
|
|
322
|
+
# And use that one in cursor link.
|
|
323
|
+
request = getattr(self, "df_request", None)
|
|
324
|
+
cursor_url = super().encode_cursor(cursor).split(":", 1)
|
|
325
|
+
req_url = self.df_request.META.get("HTTP_REFERER", None)
|
|
326
|
+
if req_url:
|
|
327
|
+
req_url = req_url.split(":", 1)
|
|
328
|
+
if cursor_url[0] != req_url[0] and req_url[0].lower() in ("http", "https"):
|
|
329
|
+
cursor_url[0] = req_url[0]
|
|
330
|
+
cursor_url = ":".join(cursor_url)
|
|
331
|
+
if (
|
|
332
|
+
request
|
|
333
|
+
and isinstance(request.accepted_renderer, JSONRenderer)
|
|
334
|
+
and "x_df_pagination" not in cursor_url
|
|
335
|
+
):
|
|
336
|
+
cursor_url += "&x_df_pagination=1"
|
|
337
|
+
return cursor_url
|
|
338
|
+
|
|
339
|
+
return MyCursorPagination
|
|
340
|
+
|
|
341
|
+
def handle_create_validation_exception(self, e, request, *args, **kwargs):
|
|
342
|
+
instance = self.new_object()
|
|
343
|
+
ser = self.get_serializer(instance, data=request.data, partial=False)
|
|
344
|
+
ser.is_valid(raise_exception=False)
|
|
345
|
+
e.detail.serializer = ser
|
|
346
|
+
raise e
|
|
347
|
+
|
|
348
|
+
def create(self, request, *args, **kwargs):
|
|
349
|
+
try:
|
|
350
|
+
return super().create(request, *args, **kwargs)
|
|
351
|
+
except ValidationError as e:
|
|
352
|
+
self.handle_create_validation_exception(e, request, *args, **kwargs)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
class SingleRecordViewSet(NewMixin, TemplateRendererMixin, viewsets.GenericViewSet):
|
|
356
|
+
def new_object(self):
|
|
357
|
+
raise NotImplementedError()
|
|
358
|
+
|
|
359
|
+
def create(self, request, *args, **kwargs):
|
|
360
|
+
raise NotImplementedError()
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
# noinspection PyUnresolvedReferences
|
|
364
|
+
class GenericViewSet(NewMixin, PutPostMixin, TemplateRendererMixin, viewsets.GenericViewSet):
|
|
365
|
+
def __init__(self, *args, **kwargs):
|
|
366
|
+
super().__init__(*args, **kwargs)
|