django-pfx 1.2.dev88__tar.gz → 1.2.dev92__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.
Files changed (109) hide show
  1. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/PKG-INFO +1 -1
  2. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/django_pfx.egg-info/PKG-INFO +1 -1
  3. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/fields.py +4 -0
  4. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/fields.py +33 -2
  5. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/models.py +8 -0
  6. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_api_doc.py +24 -0
  7. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/views.py +11 -0
  8. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/.gitignore +0 -0
  9. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/.gitlab-ci.yml +0 -0
  10. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/.pre-commit-config.yaml +0 -0
  11. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/LICENSE +0 -0
  12. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/MANIFEST.in +0 -0
  13. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/README.md +0 -0
  14. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/django_pfx.egg-info/SOURCES.txt +0 -0
  15. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/django_pfx.egg-info/dependency_links.txt +0 -0
  16. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/django_pfx.egg-info/requires.txt +0 -0
  17. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/django_pfx.egg-info/top_level.txt +0 -0
  18. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/img/pfx.png +0 -0
  19. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/img/pfx.svg +0 -0
  20. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/__init__.py +0 -0
  21. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/__init__.py +0 -0
  22. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/apidoc/__init__.py +0 -0
  23. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/apidoc/parameters.py +0 -0
  24. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/apidoc/schema.py +0 -0
  25. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/apidoc/tags.py +0 -0
  26. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/apps.py +0 -0
  27. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/decorator/__init__.py +0 -0
  28. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/decorator/rest.py +0 -0
  29. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/default_settings.py +0 -0
  30. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/exceptions.py +0 -0
  31. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/http/__init__.py +0 -0
  32. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/http/json_response.py +0 -0
  33. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  34. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +0 -0
  35. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/management/__init__.py +0 -0
  36. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/management/commands/__init__.py +0 -0
  37. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  38. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/middleware/__init__.py +0 -0
  39. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/middleware/authentication.py +0 -0
  40. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/middleware/locale.py +0 -0
  41. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/models/__init__.py +0 -0
  42. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/models/cache_mixins.py +0 -0
  43. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/models/not_null_fields.py +0 -0
  44. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/models/pfx_models.py +0 -0
  45. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  46. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/serializers/__init__.py +0 -0
  47. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/serializers/json.py +0 -0
  48. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/settings.py +0 -0
  49. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/shortcuts.py +0 -0
  50. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/storage/__init__.py +0 -0
  51. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/storage/s3_storage.py +0 -0
  52. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  53. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  54. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  55. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  56. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/test.py +0 -0
  57. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/urls.py +0 -0
  58. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/__init__.py +0 -0
  59. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/authentication_views.py +0 -0
  60. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/filters_views.py +0 -0
  61. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/locale_views.py +0 -0
  62. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  63. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  64. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/groups.py +0 -0
  65. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  66. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  67. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  68. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  69. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  70. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  71. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  72. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  73. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  74. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/subset.py +0 -0
  75. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  76. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  77. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  78. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  79. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  80. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pfx/pfxcore/views/rest_views.py +0 -0
  81. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/pyproject.toml +0 -0
  82. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/requirements.txt +0 -0
  83. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/runtest.py +0 -0
  84. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/setup.cfg +0 -0
  85. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/setup.py +0 -0
  86. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/__init__.py +0 -0
  87. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/settings/__init__.py +0 -0
  88. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/settings/ci.py +0 -0
  89. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/settings/common.py +0 -0
  90. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/settings/dev.py +0 -0
  91. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/settings/dev_custom_example.py +0 -0
  92. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/settings/dev_default.py +0 -0
  93. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/__init__.py +0 -0
  94. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/basic_api_errors.py +0 -0
  95. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/basic_api_test.py +0 -0
  96. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_auth_api.py +0 -0
  97. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_cache.py +0 -0
  98. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_fields.py +0 -0
  99. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_filters.py +0 -0
  100. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_locale_api.py +0 -0
  101. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_perm_tests.py +0 -0
  102. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_perms_api.py +0 -0
  103. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_shortcuts.py +0 -0
  104. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_timezone_middleware.py +0 -0
  105. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_tools.py +0 -0
  106. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_user_queryset.py +0 -0
  107. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_view_decorators.py +0 -0
  108. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/tests/test_view_fields.py +0 -0
  109. {django-pfx-1.2.dev88 → django-pfx-1.2.dev92}/tests/urls.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-pfx
3
- Version: 1.2.dev88
3
+ Version: 1.2.dev92
4
4
  Summary: Django PFX is a toolkit to build web APIs dedicated to be used by React progressive web app.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-pfx
3
- Version: 1.2.dev88
3
+ Version: 1.2.dev92
4
4
  Summary: Django PFX is a toolkit to build web APIs dedicated to be used by React progressive web app.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -55,6 +55,10 @@ class MinutesDurationField(models.DurationField):
55
55
  RE_HH_MM = re.compile(r'^([0-9]*):([0-5][0-9])?$')
56
56
  RE_HUMAN = re.compile(
57
57
  r'^\s*(?:([0-9]*(?:\.[0-9]*)?)h)?\s*(?:([0-9]*)m)?\s*$')
58
+ schema = dict(type='object', properties=dict(
59
+ minutes=dict(type='number', example=90),
60
+ clock_format=dict(type='string', example='01:30'),
61
+ human_format=dict(type='string', example='1h 30m')))
58
62
 
59
63
  def to_python(self, value):
60
64
  if value is None or value == '':
@@ -9,6 +9,7 @@ from django.utils.formats import date_format
9
9
  from django.utils.functional import cached_property
10
10
  from django.utils.translation import gettext_lazy as _
11
11
 
12
+ from apispec.utils import deepupdate
12
13
  from apispec.yaml_utils import load_yaml_from_docstring
13
14
 
14
15
  from pfx.pfxcore import fields as pfx_fields
@@ -222,13 +223,14 @@ class ViewField:
222
223
  properties.update(self.related_model.json_repr_schema())
223
224
  doc = inspect.getdoc(self.related_model.json_repr)
224
225
  if doc:
225
- properties.update(load_yaml_from_docstring(doc))
226
+ properties = deepupdate(
227
+ load_yaml_from_docstring(doc), properties)
226
228
  if self.json_repr:
227
229
  doc = inspect.getdoc(self.json_repr)
228
230
  if doc:
229
231
  p = load_yaml_from_docstring(doc)
230
232
  if p.pop('_extends', False):
231
- properties.update(p)
233
+ properties = deepupdate(p, properties)
232
234
  else:
233
235
  properties = p
234
236
  if properties:
@@ -241,8 +243,37 @@ class ViewField:
241
243
  properties=dict(pk=properties.get('pk')))]
242
244
  else:
243
245
  res['properties'] = properties
246
+ elif self.field_type == FieldType.MinutesDurationField:
247
+ res = pfx_fields.MinutesDurationField.schema
244
248
  elif self.field_type == FieldType.ModelObjectList:
245
249
  res['items'] = dict(type='object')
250
+ properties = {}
251
+ if self.related_model:
252
+ res['items']['format'] = str(
253
+ self.related_model._meta.verbose_name)
254
+ properties.update(self.related_model.json_repr_schema())
255
+ doc = inspect.getdoc(self.related_model.json_repr)
256
+ if doc:
257
+ properties = deepupdate(
258
+ load_yaml_from_docstring(doc), properties)
259
+ if self.json_repr:
260
+ doc = inspect.getdoc(self.json_repr)
261
+ if doc:
262
+ p = load_yaml_from_docstring(doc)
263
+ if p.pop('_extends', False):
264
+ properties = deepupdate(p, properties)
265
+ else:
266
+ properties = p
267
+ if properties:
268
+ if request:
269
+ res.pop('type', None)
270
+ res.pop('format', None)
271
+ res['oneOf'] = [
272
+ properties.get('pk'),
273
+ dict(type='object',
274
+ properties=dict(pk=properties.get('pk')))]
275
+ else:
276
+ res['items']['properties'] = properties
246
277
  res['readonly'] = self.readonly_create and self.readonly_update
247
278
  if self.choices:
248
279
  res['enum'] = list(self.choices)
@@ -201,3 +201,11 @@ class Book(CacheDependsMixin, PFXModelMixin, models.Model):
201
201
 
202
202
  def __str__(self):
203
203
  return f"{self.name}"
204
+
205
+ def json_repr(self, **values):
206
+ """JSON representation.
207
+ ---
208
+ author_name:
209
+ type: string
210
+ """
211
+ return super().json_repr(author_name=str(self.author), **values)
@@ -236,6 +236,23 @@ class ApiDocTest(TestAssertMixin, TestCase):
236
236
  self.assertJE(props, 'gender.type', 'string')
237
237
  self.assertJE(props, 'gender.enum', ['male', 'female'])
238
238
 
239
+ schema_key = self.get_val(
240
+ paths,
241
+ '/authors-annotate/{pk}.get.responses.200.content'
242
+ '.application/json.schema'
243
+ )['$ref'].split('/')[-1]
244
+ # Check ModelObjectList fields
245
+ props = spec['components']['schemas'][schema_key]['properties']
246
+ self.assertJE(props, 'books.type', 'array')
247
+ self.assertJE(props, 'books.items.type', 'object')
248
+ self.assertJE(props, 'books.items.format', 'Book')
249
+ props = self.get_val(props, 'books.items.properties')
250
+ self.assertJE(props, 'pk.type', 'number')
251
+ self.assertJE(props, 'resource_name.type', 'string')
252
+ self.assertJE(props, 'resource_reference.type', 'string')
253
+ self.assertJE(props, 'author_name.type', 'string')
254
+ self.assertJE(props, 'author_gender.type', 'string')
255
+
239
256
  schema_key = self.get_val(
240
257
  paths,
241
258
  '/books-custom-author/{pk}.get.responses.200.content'
@@ -261,6 +278,13 @@ class ApiDocTest(TestAssertMixin, TestCase):
261
278
  props = spec['components']['schemas'][schema_key]['properties']
262
279
  # Check that json_repr docstring from model is used
263
280
  self.assertJE(props, 'author.properties.new_field.type', 'string')
281
+ # Check MinutesDurationField fields json schema
282
+ self.assertJE(props, 'read_time.type', 'object')
283
+ self.assertJE(props, 'read_time.properties.minutes.type', 'number')
284
+ self.assertJE(
285
+ props, 'read_time.properties.clock_format.type', 'string')
286
+ self.assertJE(
287
+ props, 'read_time.properties.human_format.type', 'string')
264
288
 
265
289
  schema_key = self.get_val(
266
290
  paths,
@@ -125,11 +125,22 @@ class AuthorRestView(AuthorRestViewMixin, SlugDetailRestViewMixin, RestView):
125
125
  return JsonResponse(dict(value='static:more'))
126
126
 
127
127
 
128
+ def books_json_repr(book):
129
+ """JSON representation.
130
+ ---
131
+ _extends: true
132
+ author_gender:
133
+ type: string
134
+ """
135
+ return book.json_repr(author_gender=book.author.gender)
136
+
137
+
128
138
  @rest_doc('/<int:id>', 'get', summary="Get custom author", groups=["custom"])
129
139
  @rest_view("/authors-annotate")
130
140
  class AuthorAnnotateRestView(AuthorRestView):
131
141
  fields = [
132
142
  'first_name', 'last_name', 'slug',
143
+ VF('books', json_repr=books_json_repr),
133
144
  'books_count', 'books_count_annotate', 'books_count_prop']
134
145
  list_fields = [
135
146
  'first_name', 'last_name', 'slug',
File without changes
File without changes
File without changes
File without changes