django-pfx 1.4.dev80__tar.gz → 1.4.dev82__tar.gz
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.
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/PKG-INFO +1 -1
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/django_pfx.egg-info/PKG-INFO +1 -1
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/django_pfx.egg-info/SOURCES.txt +3 -0
- django_pfx-1.4.dev82/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +16 -6
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/__init__.py +1 -0
- django_pfx-1.4.dev82/pfx/pfxcore/models/ordered_model_mixin.py +140 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/__init__.py +1 -0
- django_pfx-1.4.dev82/pfx/pfxcore/views/ordered_rest_view_mixin.py +54 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/rest_views.py +6 -2
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/setup.cfg +1 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/__init__.py +1 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_client.py +2 -1
- django_pfx-1.4.dev82/tests/tests/test_ordered_rest_view_mixin.py +498 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/views.py +9 -0
- django_pfx-1.4.dev80/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/.gitignore +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/.gitlab-ci.yml +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/.pre-commit-config.yaml +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/LICENSE +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/MANIFEST.in +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/README.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/Makefile +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/conf.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/index.rst +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/api.views.rst +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/authentication.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/decorator.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/getting_started.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/model.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/profiling.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/settings.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/doc/source/testing.md +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/img/pfx.png +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/img/pfx.svg +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/make_messages +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/manage.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/fields.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/authentication_views.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pfx/settings/dev.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/pyproject.toml +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/requirements.txt +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/serve-doc +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/setup.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/models.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/settings/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/settings/ci.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/settings/common.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/settings/dev.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_auth_api.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_fields.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_permissions.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_post_migrate_groups_update.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests/urls.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/settings/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/settings/ci.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/settings/common.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/settings/dev.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/tests/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/tests/test_api.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/urls.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_base_user/views.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/models.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/settings/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/settings/ci.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/settings/common.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/settings/dev.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/tests/__init__.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/tests/test_api.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/urls.py +0 -0
- {django_pfx-1.4.dev80 → django_pfx-1.4.dev82}/tests_custom_user/views.py +0 -0
|
@@ -71,6 +71,7 @@ pfx/pfxcore/models/abstract_pfx_base_user.py
|
|
|
71
71
|
pfx/pfxcore/models/cache_mixins.py
|
|
72
72
|
pfx/pfxcore/models/login_ban.py
|
|
73
73
|
pfx/pfxcore/models/not_null_fields.py
|
|
74
|
+
pfx/pfxcore/models/ordered_model_mixin.py
|
|
74
75
|
pfx/pfxcore/models/otp_user_mixin.py
|
|
75
76
|
pfx/pfxcore/models/pfx_models.py
|
|
76
77
|
pfx/pfxcore/models/pfx_user.py
|
|
@@ -90,6 +91,7 @@ pfx/pfxcore/views/authentication_views.py
|
|
|
90
91
|
pfx/pfxcore/views/fields.py
|
|
91
92
|
pfx/pfxcore/views/filters_views.py
|
|
92
93
|
pfx/pfxcore/views/locale_views.py
|
|
94
|
+
pfx/pfxcore/views/ordered_rest_view_mixin.py
|
|
93
95
|
pfx/pfxcore/views/rest_views.py
|
|
94
96
|
pfx/pfxcore/views/parameters/__init__.py
|
|
95
97
|
pfx/pfxcore/views/parameters/date_format.py
|
|
@@ -136,6 +138,7 @@ tests/tests/test_client.py
|
|
|
136
138
|
tests/tests/test_fields.py
|
|
137
139
|
tests/tests/test_filters.py
|
|
138
140
|
tests/tests/test_locale_api.py
|
|
141
|
+
tests/tests/test_ordered_rest_view_mixin.py
|
|
139
142
|
tests/tests/test_perm_tests.py
|
|
140
143
|
tests/tests/test_permissions.py
|
|
141
144
|
tests/tests/test_perms_api.py
|
|
Binary file
|
|
@@ -7,7 +7,7 @@ msgid ""
|
|
|
7
7
|
msgstr ""
|
|
8
8
|
"Project-Id-Version: \n"
|
|
9
9
|
"Report-Msgid-Bugs-To: \n"
|
|
10
|
-
"POT-Creation-Date: 2025-01-
|
|
10
|
+
"POT-Creation-Date: 2025-01-31 09:52+0100\n"
|
|
11
11
|
"PO-Revision-Date: 2021-06-22 23:31+0200\n"
|
|
12
12
|
"Last-Translator: \n"
|
|
13
13
|
"Language-Team: \n"
|
|
@@ -267,27 +267,37 @@ msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
|
|
|
267
267
|
msgid "Invalid value for {filter} filter"
|
|
268
268
|
msgstr "Valeur invalide pour le filtre {filter}"
|
|
269
269
|
|
|
270
|
-
#: views/
|
|
270
|
+
#: views/ordered_rest_view_mixin.py:32
|
|
271
|
+
#, python-brace-format
|
|
272
|
+
msgid "object parameter is mandatory for move={move}."
|
|
273
|
+
msgstr "Le paramètre object est requis pour move={move}."
|
|
274
|
+
|
|
275
|
+
#: views/ordered_rest_view_mixin.py:39
|
|
276
|
+
#, python-brace-format
|
|
277
|
+
msgid "object {pk} does not exists in this move context."
|
|
278
|
+
msgstr "object {pk} n'existe pas dans ce contexte de déplacement."
|
|
279
|
+
|
|
280
|
+
#: views/rest_views.py:246
|
|
271
281
|
#, python-brace-format
|
|
272
282
|
msgid "{obj} cannot be deleted because it is referenced by other objects."
|
|
273
283
|
msgstr ""
|
|
274
284
|
"{obj} ne peut pas être supprimé car il est référencé par d’autres objets."
|
|
275
285
|
|
|
276
|
-
#: views/rest_views.py:
|
|
286
|
+
#: views/rest_views.py:331
|
|
277
287
|
#, python-brace-format
|
|
278
288
|
msgid "{model} {obj} created."
|
|
279
289
|
msgstr "{model} {obj} créé."
|
|
280
290
|
|
|
281
|
-
#: views/rest_views.py:
|
|
291
|
+
#: views/rest_views.py:332
|
|
282
292
|
#, python-brace-format
|
|
283
293
|
msgid "{model} {obj} updated."
|
|
284
294
|
msgstr "{model} {obj} modifié."
|
|
285
295
|
|
|
286
|
-
#: views/rest_views.py:
|
|
296
|
+
#: views/rest_views.py:1157
|
|
287
297
|
#, python-brace-format
|
|
288
298
|
msgid "{model} {obj} deleted."
|
|
289
299
|
msgstr "{model} {obj} supprimé."
|
|
290
300
|
|
|
291
|
-
#: views/rest_views.py:
|
|
301
|
+
#: views/rest_views.py:1256 views/rest_views.py:1296
|
|
292
302
|
msgid "Unexpected storage error"
|
|
293
303
|
msgstr "Erreur de stockage inattendue"
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
from django.db.models import F, Max, Min
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class OrderedModelMixin(models.Model):
|
|
6
|
+
ordered_by = []
|
|
7
|
+
ordered_default = 'last'
|
|
8
|
+
|
|
9
|
+
seq = models.PositiveBigIntegerField("Séquence")
|
|
10
|
+
|
|
11
|
+
class Meta:
|
|
12
|
+
abstract = True
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def _ordered_by_values(self):
|
|
16
|
+
return {self.serializable_value(f) for f in self.ordered_by}
|
|
17
|
+
|
|
18
|
+
def __init__(self, *args, **kwargs):
|
|
19
|
+
super().__init__(*args, **kwargs)
|
|
20
|
+
self.__previous_ordered_by_values = self._ordered_by_values
|
|
21
|
+
|
|
22
|
+
def clean_fields(self, exclude=None):
|
|
23
|
+
if not self.seq:
|
|
24
|
+
self.seq = self._order_default
|
|
25
|
+
super().clean_fields(exclude=exclude)
|
|
26
|
+
|
|
27
|
+
def save(self, *args, **kwargs):
|
|
28
|
+
if not self.seq:
|
|
29
|
+
self.seq = self._order_default
|
|
30
|
+
super().save(*args, **kwargs)
|
|
31
|
+
if self.__previous_ordered_by_values != self._ordered_by_values:
|
|
32
|
+
if self.ordered_default == 'first':
|
|
33
|
+
self.top()
|
|
34
|
+
else:
|
|
35
|
+
self.bottom()
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def _order_qs(self):
|
|
39
|
+
return self.__class__._default_manager.filter(**{
|
|
40
|
+
f: getattr(self, f) for f in self.ordered_by})
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def _order_max(self):
|
|
44
|
+
return self._order_qs.aggregate(Max('seq'))['seq__max']
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def _order_min(self):
|
|
48
|
+
return self._order_qs.aggregate(Min('seq'))['seq__min']
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def _order_default(self):
|
|
52
|
+
if self.ordered_default == 'first':
|
|
53
|
+
min = self._order_min
|
|
54
|
+
res = min is None and 1 or min - 1
|
|
55
|
+
if res == 0:
|
|
56
|
+
self.first._order_shift()
|
|
57
|
+
return 1
|
|
58
|
+
return res
|
|
59
|
+
else:
|
|
60
|
+
return (self._order_max or 0) + 1
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def previous(self):
|
|
64
|
+
return self._order_qs.filter(
|
|
65
|
+
seq__lt=self.seq).order_by('seq', 'pk').last()
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def next(self):
|
|
69
|
+
return self._order_qs.filter(
|
|
70
|
+
seq__gt=self.seq).order_by('seq', 'pk').first()
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def first(self):
|
|
74
|
+
return self._order_qs.order_by('seq', 'pk').first()
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def last(self):
|
|
78
|
+
return self._order_qs.order_by('seq', 'pk').last()
|
|
79
|
+
|
|
80
|
+
def _order_shift(self):
|
|
81
|
+
self._order_qs.filter(seq__gte=self.seq).update(
|
|
82
|
+
seq=F('seq') + 1)
|
|
83
|
+
|
|
84
|
+
def _order_switch(self, other):
|
|
85
|
+
other_seq = other.seq
|
|
86
|
+
other.seq = self.seq
|
|
87
|
+
other.save(update_fields=['seq'])
|
|
88
|
+
self.seq = other_seq
|
|
89
|
+
self.save(update_fields=['seq'])
|
|
90
|
+
|
|
91
|
+
def up(self):
|
|
92
|
+
previous = self.previous
|
|
93
|
+
if not previous:
|
|
94
|
+
return
|
|
95
|
+
self._order_switch(previous)
|
|
96
|
+
|
|
97
|
+
def down(self):
|
|
98
|
+
next = self.next
|
|
99
|
+
if not next:
|
|
100
|
+
return
|
|
101
|
+
self._order_switch(next)
|
|
102
|
+
|
|
103
|
+
def top(self):
|
|
104
|
+
first = self.first
|
|
105
|
+
if first.pk == self.pk:
|
|
106
|
+
return
|
|
107
|
+
seq = first.seq - 1
|
|
108
|
+
if seq == 0:
|
|
109
|
+
first._order_shift()
|
|
110
|
+
seq = 1
|
|
111
|
+
self.seq = seq
|
|
112
|
+
self.save(update_fields=['seq'])
|
|
113
|
+
|
|
114
|
+
def bottom(self):
|
|
115
|
+
last = self.last
|
|
116
|
+
if last.pk == self.pk:
|
|
117
|
+
return
|
|
118
|
+
self.seq = last.seq + 1
|
|
119
|
+
self.save(update_fields=['seq'])
|
|
120
|
+
|
|
121
|
+
def above(self, other):
|
|
122
|
+
prev = other.previous
|
|
123
|
+
if not prev:
|
|
124
|
+
return self.top()
|
|
125
|
+
seq = other.seq - 1
|
|
126
|
+
if seq == prev.seq:
|
|
127
|
+
other._order_shift()
|
|
128
|
+
seq += 1
|
|
129
|
+
self.seq = seq
|
|
130
|
+
self.save(update_fields=['seq'])
|
|
131
|
+
|
|
132
|
+
def below(self, other):
|
|
133
|
+
next = other.next
|
|
134
|
+
if not next:
|
|
135
|
+
return self.bottom()
|
|
136
|
+
seq = other.seq + 1
|
|
137
|
+
if seq == next.seq:
|
|
138
|
+
next._order_shift()
|
|
139
|
+
self.seq = seq
|
|
140
|
+
self.save(update_fields=['seq'])
|
|
@@ -8,6 +8,7 @@ from .authentication_views import (
|
|
|
8
8
|
from .fields import VF, FieldType, ViewField, ViewModelField
|
|
9
9
|
from .filters_views import Filter, FilterGroup, ModelFilter
|
|
10
10
|
from .locale_views import LocaleRestView
|
|
11
|
+
from .ordered_rest_view_mixin import OrderedRestViewMixin
|
|
11
12
|
from .rest_views import (
|
|
12
13
|
BaseRestView,
|
|
13
14
|
BodyMixin,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
3
|
+
from django.db import transaction
|
|
4
|
+
from django.utils.translation import gettext_lazy as _
|
|
5
|
+
|
|
6
|
+
from pfx.pfxcore.exceptions import APIError
|
|
7
|
+
from pfx.pfxcore.models import OrderedModelMixin
|
|
8
|
+
from pfx.pfxcore.shortcuts import f
|
|
9
|
+
|
|
10
|
+
from .rest_views import ModelResponseMixin
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class OrderedRestViewMixin(ModelResponseMixin):
|
|
14
|
+
"""Extension mixin for OrderedModelMixin models."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, *args, **kwargs):
|
|
17
|
+
if not issubclass(self.model, OrderedModelMixin):
|
|
18
|
+
raise TypeError("model is not a subclass of OrderedModelMixin")
|
|
19
|
+
super().__init__(*args, **kwargs)
|
|
20
|
+
|
|
21
|
+
def is_valid(self, obj, created=False, **kwargs):
|
|
22
|
+
with transaction.atomic():
|
|
23
|
+
res = super().is_valid(obj, created, **kwargs)
|
|
24
|
+
self.apply_move(obj)
|
|
25
|
+
return res
|
|
26
|
+
|
|
27
|
+
def apply_move(self, obj):
|
|
28
|
+
def get_object(move):
|
|
29
|
+
pk = self.request.GET.get('object')
|
|
30
|
+
if not pk:
|
|
31
|
+
raise APIError(f(
|
|
32
|
+
_("object parameter is mandatory for move={move}."),
|
|
33
|
+
move=move))
|
|
34
|
+
try:
|
|
35
|
+
return self.get_queryset(
|
|
36
|
+
from_queryset=obj._order_qs).get(pk=pk)
|
|
37
|
+
except ObjectDoesNotExist:
|
|
38
|
+
raise APIError(f(
|
|
39
|
+
_("object {pk} does not exists in this move context."),
|
|
40
|
+
pk=pk))
|
|
41
|
+
|
|
42
|
+
move = self.request.GET.get('move')
|
|
43
|
+
if move == 'up':
|
|
44
|
+
obj.up()
|
|
45
|
+
elif move == 'down':
|
|
46
|
+
obj.down()
|
|
47
|
+
elif move == 'bottom':
|
|
48
|
+
obj.bottom()
|
|
49
|
+
elif move == 'top':
|
|
50
|
+
obj.top()
|
|
51
|
+
elif move == 'above':
|
|
52
|
+
obj.above(get_object(move))
|
|
53
|
+
elif move == 'below':
|
|
54
|
+
obj.below(get_object(move))
|
|
@@ -80,7 +80,9 @@ class ModelMixin():
|
|
|
80
80
|
raise Exception("The queryset must be a UserFilteredQuerySetMixin")
|
|
81
81
|
return qs
|
|
82
82
|
|
|
83
|
-
def get_queryset(
|
|
83
|
+
def get_queryset(
|
|
84
|
+
self, select_related=None, prefetch_related=None,
|
|
85
|
+
from_queryset=None):
|
|
84
86
|
"""Get the queryset for the view model.
|
|
85
87
|
|
|
86
88
|
The returned queryset is filtered according to user rights.
|
|
@@ -89,10 +91,12 @@ class ModelMixin():
|
|
|
89
91
|
:type select_related: :class:`list[str]`
|
|
90
92
|
:param prefetch_related: Arguments for queryset prefetch_related
|
|
91
93
|
:type prefetch_related: :class:`list[str]`
|
|
94
|
+
:param from_queryset: A source queryset
|
|
92
95
|
:returns: The queryset
|
|
93
96
|
:rtype: :class:`django.db.models.QuerySet`
|
|
94
97
|
"""
|
|
95
|
-
qs = self.apply_user_filter(
|
|
98
|
+
qs = self.apply_user_filter(
|
|
99
|
+
from_queryset or self.model._default_manager.all())
|
|
96
100
|
if select_related:
|
|
97
101
|
qs = qs.select_related(*select_related)
|
|
98
102
|
if prefetch_related:
|
|
@@ -9,6 +9,7 @@ from .test_client import TestApiClient
|
|
|
9
9
|
from .test_fields import FieldsTest
|
|
10
10
|
from .test_filters import FiltersTest
|
|
11
11
|
from .test_locale_api import LocaleAPITest
|
|
12
|
+
from .test_ordered_rest_view_mixin import TestOrderedRestViewMixin
|
|
12
13
|
from .test_perm_tests import PermTestsTest
|
|
13
14
|
from .test_permissions import TestPermissions
|
|
14
15
|
from .test_perms_api import PermsAPITest
|
|
@@ -11,6 +11,7 @@ from pfx.pfxcore.models import JSONReprMixin
|
|
|
11
11
|
from pfx.pfxcore.test import APIClient, TestAssertMixin
|
|
12
12
|
from pfx.pfxcore.views import RestView
|
|
13
13
|
from tests.models import User
|
|
14
|
+
from tests.views import FakeViewMixin
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class TestModel(JSONReprMixin, models.Model):
|
|
@@ -26,7 +27,7 @@ class TestModel(JSONReprMixin, models.Model):
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
@rest_view("/test")
|
|
29
|
-
class TestRestView(RestView):
|
|
30
|
+
class TestRestView(FakeViewMixin, RestView):
|
|
30
31
|
default_public = True
|
|
31
32
|
model = TestModel
|
|
32
33
|
|