django-pfx 1.4.dev52__tar.gz → 1.4.dev56__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.dev52 → django_pfx-1.4.dev56}/PKG-INFO +1 -1
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/django_pfx.egg-info/PKG-INFO +1 -1
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +4 -4
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/pfx_models.py +1 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/filters_views.py +11 -4
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/rest_views.py +72 -21
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/models.py +1 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/basic_api_errors.py +4 -3
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/basic_api_test.py +13 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/views.py +1 -1
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/.gitignore +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/.gitlab-ci.yml +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/.pre-commit-config.yaml +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/LICENSE +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/MANIFEST.in +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/README.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/django_pfx.egg-info/SOURCES.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/Makefile +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/conf.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/index.rst +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/api.views.rst +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/authentication.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/decorator.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/getting_started.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/model.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/profiling.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/settings.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/doc/source/testing.md +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/img/pfx.png +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/img/pfx.svg +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/make_messages +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/manage.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/fields.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/authentication_views.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/settings/dev.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pyproject.toml +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/requirements.txt +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/serve-doc +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/setup.cfg +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/setup.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/settings/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/settings/ci.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/settings/common.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/settings/dev.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/__init__.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_auth_api.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_client.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_fields.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/tests/urls.py +0 -0
|
@@ -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: 2024-
|
|
10
|
+
"POT-Creation-Date: 2024-12-10 13:34+0100\n"
|
|
11
11
|
"PO-Revision-Date: 2021-06-22 23:31+0200\n"
|
|
12
12
|
"Last-Translator: \n"
|
|
13
13
|
"Language-Team: \n"
|
|
@@ -254,7 +254,7 @@ msgstr ""
|
|
|
254
254
|
msgid "A new authentication code has been sent by email."
|
|
255
255
|
msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
|
|
256
256
|
|
|
257
|
-
#: views/filters_views.py:
|
|
257
|
+
#: views/filters_views.py:81
|
|
258
258
|
#, python-brace-format
|
|
259
259
|
msgid "Invalid value for {filter} filter"
|
|
260
260
|
msgstr "Valeur invalide pour le filtre {filter}"
|
|
@@ -275,11 +275,11 @@ msgstr "{model} {obj} créé."
|
|
|
275
275
|
msgid "{model} {obj} updated."
|
|
276
276
|
msgstr "{model} {obj} modifié."
|
|
277
277
|
|
|
278
|
-
#: views/rest_views.py:
|
|
278
|
+
#: views/rest_views.py:1086
|
|
279
279
|
#, python-brace-format
|
|
280
280
|
msgid "{model} {obj} deleted."
|
|
281
281
|
msgstr "{model} {obj} supprimé."
|
|
282
282
|
|
|
283
|
-
#: views/rest_views.py:
|
|
283
|
+
#: views/rest_views.py:1178 views/rest_views.py:1218
|
|
284
284
|
msgid "Unexpected storage error"
|
|
285
285
|
msgstr "Erreur de stockage inattendue"
|
|
@@ -34,8 +34,8 @@ class Filter():
|
|
|
34
34
|
def __init__(
|
|
35
35
|
self, name, label, type=None, filter_func=None,
|
|
36
36
|
filter_func_and=False, filter_func_list=False, choices=None,
|
|
37
|
-
related_model=None,
|
|
38
|
-
empty_value=True):
|
|
37
|
+
related_model=None, related_model_api=None,
|
|
38
|
+
technical=False, defaults=None, empty_value=True):
|
|
39
39
|
self.name = name
|
|
40
40
|
self.label = label
|
|
41
41
|
self.type = type
|
|
@@ -44,6 +44,7 @@ class Filter():
|
|
|
44
44
|
self.filter_func_list = filter_func_list
|
|
45
45
|
self.choices = choices
|
|
46
46
|
self.related_model = related_model
|
|
47
|
+
self.related_model_api = related_model_api
|
|
47
48
|
self.technical = technical
|
|
48
49
|
self.defaults = defaults or []
|
|
49
50
|
self.empty_value = empty_value
|
|
@@ -62,6 +63,7 @@ class Filter():
|
|
|
62
63
|
dict(label=_(v), value=k) for k, v in self.choices]
|
|
63
64
|
if self.related_model:
|
|
64
65
|
res['related_model'] = str(self.related_model.__name__)
|
|
66
|
+
res['api'] = self.related_model_api
|
|
65
67
|
return res
|
|
66
68
|
|
|
67
69
|
def _parse_value(self, value):
|
|
@@ -99,8 +101,8 @@ class ModelFilter(Filter):
|
|
|
99
101
|
def __init__(
|
|
100
102
|
self, model, name, label=None, type=None,
|
|
101
103
|
filter_func=None, filter_func_and=False, filter_func_list=False,
|
|
102
|
-
choices=None, related_model=None,
|
|
103
|
-
empty_value=None):
|
|
104
|
+
choices=None, related_model=None, related_model_api=None,
|
|
105
|
+
technical=False, defaults=None, empty_value=None):
|
|
104
106
|
self.model = model
|
|
105
107
|
self.field = model._meta.get_field(name)
|
|
106
108
|
if empty_value is None:
|
|
@@ -113,6 +115,11 @@ class ModelFilter(Filter):
|
|
|
113
115
|
related_model or (
|
|
114
116
|
self.field.remote_field and
|
|
115
117
|
self.field.remote_field.model),
|
|
118
|
+
related_model_api or (
|
|
119
|
+
self.field.remote_field and
|
|
120
|
+
self.field.remote_field.model and
|
|
121
|
+
hasattr(self.field.remote_field.model, 'api') and
|
|
122
|
+
self.field.remote_field.model.api),
|
|
116
123
|
technical=technical, defaults=defaults, empty_value=empty_value)
|
|
117
124
|
|
|
118
125
|
@property
|
|
@@ -143,8 +143,8 @@ class ModelMixin():
|
|
|
143
143
|
def _process_fields(cls, fields):
|
|
144
144
|
if not fields:
|
|
145
145
|
return {
|
|
146
|
-
|
|
147
|
-
for
|
|
146
|
+
_f.name: ViewField.from_model_field(_f.name, _f)
|
|
147
|
+
for _f in cls.model._meta.fields}
|
|
148
148
|
|
|
149
149
|
def _field(e):
|
|
150
150
|
if isinstance(e, ViewField):
|
|
@@ -178,8 +178,8 @@ class ModelMixin():
|
|
|
178
178
|
return cache.get_or_set(
|
|
179
179
|
class_key(cls, 'fields', 'select_related'),
|
|
180
180
|
lambda: set([
|
|
181
|
-
|
|
182
|
-
for
|
|
181
|
+
_f for field in cls.get_fields().values()
|
|
182
|
+
for _f in field.select_related]),
|
|
183
183
|
None)
|
|
184
184
|
|
|
185
185
|
@classmethod
|
|
@@ -188,8 +188,8 @@ class ModelMixin():
|
|
|
188
188
|
return cache.get_or_set(
|
|
189
189
|
class_key(cls, 'fields', 'prefetch_related'),
|
|
190
190
|
lambda: set([
|
|
191
|
-
|
|
192
|
-
for
|
|
191
|
+
_f for field in cls.get_fields().values()
|
|
192
|
+
for _f in field.prefetch_related]),
|
|
193
193
|
None)
|
|
194
194
|
|
|
195
195
|
@property
|
|
@@ -286,8 +286,8 @@ class ModelResponseMixin(ModelMixin):
|
|
|
286
286
|
:rtype: :class:`JsonResponse`
|
|
287
287
|
"""
|
|
288
288
|
return JsonResponse(self.serialize_object(o, **{
|
|
289
|
-
|
|
290
|
-
for
|
|
289
|
+
_f.alias: _f.to_json(o, self.format_date)
|
|
290
|
+
for _f in self.get_fields().values()}, meta=meta))
|
|
291
291
|
|
|
292
292
|
def validate(self, obj, created=False, **kwargs):
|
|
293
293
|
"""Validate an object instance.
|
|
@@ -434,8 +434,8 @@ class BodyMixin:
|
|
|
434
434
|
"""
|
|
435
435
|
if fields is None:
|
|
436
436
|
fields = [
|
|
437
|
-
|
|
438
|
-
if not isinstance(
|
|
437
|
+
_f.name for _f in model._meta.get_fields()
|
|
438
|
+
if not isinstance(_f, AutoFieldMixin)]
|
|
439
439
|
obj = model(**{
|
|
440
440
|
k: v for k, v in self.deserialize_body().items() if k in fields})
|
|
441
441
|
if validate:
|
|
@@ -531,6 +531,15 @@ class ListRestViewMixin(ModelResponseMixin):
|
|
|
531
531
|
self.list_fields or self.fields)), None))
|
|
532
532
|
return self._list_fields
|
|
533
533
|
|
|
534
|
+
def get_list_meta_filters(self):
|
|
535
|
+
"""Return the filters metadata for lists.
|
|
536
|
+
|
|
537
|
+
:returns: The filters metadata generator
|
|
538
|
+
:rtype: :class:`generator`
|
|
539
|
+
"""
|
|
540
|
+
for _f in self.filters:
|
|
541
|
+
yield _f.meta
|
|
542
|
+
|
|
534
543
|
def search_filter(self, search): # pragma: no cover
|
|
535
544
|
"""Return the django filters for the default text search.
|
|
536
545
|
|
|
@@ -577,7 +586,7 @@ class ListRestViewMixin(ModelResponseMixin):
|
|
|
577
586
|
if get_bool(self.request.GET, 'filters', default_all):
|
|
578
587
|
meta['filters'] = cache.get_or_set(
|
|
579
588
|
class_key(self.__class__, 'meta', 'filters'),
|
|
580
|
-
lambda: [
|
|
589
|
+
lambda: [_f.meta for _f in self.filters],
|
|
581
590
|
None)
|
|
582
591
|
if get_bool(self.request.GET, 'orders', default_all):
|
|
583
592
|
meta['orders'] = cache.get_or_set(
|
|
@@ -681,8 +690,8 @@ class ListRestViewMixin(ModelResponseMixin):
|
|
|
681
690
|
return cache.get_or_set(
|
|
682
691
|
class_key(self.__class__, 'list_fields', 'select_related'),
|
|
683
692
|
lambda: set([
|
|
684
|
-
|
|
685
|
-
for
|
|
693
|
+
_f for field in self.get_list_fields().values()
|
|
694
|
+
for _f in field.select_related]),
|
|
686
695
|
None)
|
|
687
696
|
|
|
688
697
|
def get_list_fields_prefetch_related(self):
|
|
@@ -690,8 +699,8 @@ class ListRestViewMixin(ModelResponseMixin):
|
|
|
690
699
|
return cache.get_or_set(
|
|
691
700
|
class_key(self.__class__, 'list_fields', 'prefetch_related'),
|
|
692
701
|
lambda: set([
|
|
693
|
-
|
|
694
|
-
for
|
|
702
|
+
_f for field in self.get_list_fields().values()
|
|
703
|
+
for _f in field.prefetch_related]),
|
|
695
704
|
None)
|
|
696
705
|
|
|
697
706
|
def get_list_result(self, qs):
|
|
@@ -708,8 +717,8 @@ class ListRestViewMixin(ModelResponseMixin):
|
|
|
708
717
|
*self.get_list_fields_prefetch_related())
|
|
709
718
|
for o in qs:
|
|
710
719
|
yield self.serialize_object(o, **{
|
|
711
|
-
|
|
712
|
-
for
|
|
720
|
+
_f.alias: _f.to_json(o, self.format_date)
|
|
721
|
+
for _f in self.get_list_fields().values()})
|
|
713
722
|
|
|
714
723
|
def get_short_list_result(self, qs):
|
|
715
724
|
"""Get a generator to serialize each result in a queryset.
|
|
@@ -1124,11 +1133,41 @@ class MediaRestViewMixin(ModelMixin):
|
|
|
1124
1133
|
---
|
|
1125
1134
|
get:
|
|
1126
1135
|
summary: Get upload URL
|
|
1127
|
-
description:
|
|
1136
|
+
description: |
|
|
1137
|
+
Get upload URL for a `MediaField` field.
|
|
1138
|
+
|
|
1139
|
+
You can upload a file ont the received URL. When the upload
|
|
1140
|
+
query is done, you have to confirm the process with an
|
|
1141
|
+
update request (`PUT`) on {model}. The body of this request
|
|
1142
|
+
must contain the name of the `MediaField` with the contents
|
|
1143
|
+
of the `file` value in the response of this request.
|
|
1144
|
+
|
|
1145
|
+
1. `GET /<int:pk>/<str:field>/upload-url/<str:filename>`
|
|
1146
|
+
→ `data`
|
|
1147
|
+
2. `PUT data.url aFile Content-Type: aFile.type`
|
|
1148
|
+
3. `PUT /<int:pk> {{field: data.file}}`
|
|
1128
1149
|
parameters extras:
|
|
1129
|
-
pk:
|
|
1130
|
-
field:
|
|
1131
|
-
|
|
1150
|
+
pk: The {model} pk.
|
|
1151
|
+
field: The {model} field name. Must be the name of
|
|
1152
|
+
a `MediaField` field.
|
|
1153
|
+
filename: The desired filename.
|
|
1154
|
+
responses:
|
|
1155
|
+
200:
|
|
1156
|
+
description: The upload URL
|
|
1157
|
+
content:
|
|
1158
|
+
application/json:
|
|
1159
|
+
schema:
|
|
1160
|
+
properties:
|
|
1161
|
+
url:
|
|
1162
|
+
type: string
|
|
1163
|
+
format: uri
|
|
1164
|
+
file:
|
|
1165
|
+
type: object
|
|
1166
|
+
properties:
|
|
1167
|
+
name:
|
|
1168
|
+
type: string
|
|
1169
|
+
key:
|
|
1170
|
+
type: string
|
|
1132
1171
|
"""
|
|
1133
1172
|
obj = self.get_object(pk=pk)
|
|
1134
1173
|
try:
|
|
@@ -1158,6 +1197,18 @@ class MediaRestViewMixin(ModelMixin):
|
|
|
1158
1197
|
parameters extras:
|
|
1159
1198
|
pk: the {model} pk
|
|
1160
1199
|
field: the {model} field name
|
|
1200
|
+
responses:
|
|
1201
|
+
200:
|
|
1202
|
+
description: The file URL, if `redirect` is `false`.
|
|
1203
|
+
content:
|
|
1204
|
+
application/json:
|
|
1205
|
+
schema:
|
|
1206
|
+
properties:
|
|
1207
|
+
url:
|
|
1208
|
+
type: string
|
|
1209
|
+
format: uri
|
|
1210
|
+
302:
|
|
1211
|
+
description: The redirect, if `redirect` is `true`.
|
|
1161
1212
|
"""
|
|
1162
1213
|
obj = self.get_object(pk=pk)
|
|
1163
1214
|
try:
|
|
@@ -109,6 +109,7 @@ class UserAuthorQuerySet(UserFilteredQuerySetMixin, models.QuerySet):
|
|
|
109
109
|
|
|
110
110
|
class Author(CacheableMixin, JSONReprMixin, models.Model):
|
|
111
111
|
CACHED_PROPERTIES = ['books_count']
|
|
112
|
+
api = '/authors'
|
|
112
113
|
|
|
113
114
|
first_name = models.CharField(_("First Name"), max_length=30)
|
|
114
115
|
last_name = models.CharField(_("Last Name"), max_length=30)
|
|
@@ -59,7 +59,8 @@ class BasicAPIErrorTest(TestAssertMixin, TestCase):
|
|
|
59
59
|
"new_password": "Wrong stuffs",
|
|
60
60
|
}''')
|
|
61
61
|
self.assertRC(response, 422)
|
|
62
|
-
self.
|
|
63
|
-
|
|
62
|
+
self.assertIn(self.get_val(response, 'message'), [
|
|
63
|
+
"JSON Malformed Illegal trailing comma before end "
|
|
64
|
+
"of object: line 3 column 47 (char 96)", # python >= 3.13
|
|
64
65
|
"JSON Malformed Expecting property name enclosed in "
|
|
65
|
-
"double quotes: line 4 column 17 (char 114)")
|
|
66
|
+
"double quotes: line 4 column 17 (char 114)"]) # python <= 3.12
|
|
@@ -224,6 +224,7 @@ class BasicAPITest(TestAssertMixin, TestCase):
|
|
|
224
224
|
"label": "Types",
|
|
225
225
|
"name": "types",
|
|
226
226
|
"related_model": "BookType",
|
|
227
|
+
"api": "/book-types",
|
|
227
228
|
"technical": False,
|
|
228
229
|
"type": "ModelObject"
|
|
229
230
|
}
|
|
@@ -286,6 +287,18 @@ class BasicAPITest(TestAssertMixin, TestCase):
|
|
|
286
287
|
|
|
287
288
|
response = self.client.get('/api/books/meta/list')
|
|
288
289
|
self.assertRC(response, 200)
|
|
290
|
+
|
|
291
|
+
self.assertJE(response, 'filters.@0.items.@0', {
|
|
292
|
+
"empty_value": False,
|
|
293
|
+
"is_group": False,
|
|
294
|
+
"label": "Author",
|
|
295
|
+
"name": "author",
|
|
296
|
+
"related_model": "Author",
|
|
297
|
+
"api": "/authors",
|
|
298
|
+
"technical": False,
|
|
299
|
+
"type": "ModelObject"
|
|
300
|
+
})
|
|
301
|
+
|
|
289
302
|
self.assertJIn(response, 'orders', 'pk')
|
|
290
303
|
self.assertJIn(response, 'orders', 'name')
|
|
291
304
|
self.assertJIn(response, 'orders', 'author')
|
|
@@ -64,7 +64,7 @@ class AuthorRestView(AuthorRestViewMixin, SlugDetailRestViewMixin, RestView):
|
|
|
64
64
|
Filter(
|
|
65
65
|
'heroic_fantasy', _("Heroic Fantasy"),
|
|
66
66
|
FieldType.BooleanField, heroic_fantasy_filter),
|
|
67
|
-
ModelFilter(Author, 'types')
|
|
67
|
+
ModelFilter(Author, 'types', related_model_api='/book-types')
|
|
68
68
|
]),
|
|
69
69
|
FilterGroup('custom', _("Custom"), [
|
|
70
70
|
ModelFilter(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/models/user_filtered_queryset_mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/otp_code_email.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/welcome_email.txt
RENAMED
|
File without changes
|
{django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/templates/registration/welcome_subject.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/media_redirect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset_page_size.py
RENAMED
|
File without changes
|
{django_pfx-1.4.dev52 → django_pfx-1.4.dev56}/pfx/pfxcore/views/parameters/subset_page_subset.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|