django-pfx 1.2.dev107__tar.gz → 1.2.dev110__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 (122) hide show
  1. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/PKG-INFO +6 -8
  2. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/README.md +1 -4
  3. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/django_pfx.egg-info/PKG-INFO +6 -8
  4. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/django_pfx.egg-info/requires.txt +1 -1
  5. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/index.rst +1 -7
  6. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/decorator.md +18 -6
  7. django-pfx-1.2.dev110/doc/source/getting_started.md +179 -0
  8. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/internationalisation.md +1 -1
  9. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/model.md +21 -13
  10. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/pfx_views.md +49 -21
  11. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/testing.md +40 -13
  12. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/authentication_views.py +3 -1
  13. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/setup.cfg +5 -4
  14. django-pfx-1.2.dev107/doc/source/getting_started.md +0 -81
  15. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/.gitignore +0 -0
  16. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/.gitlab-ci.yml +0 -0
  17. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/.pre-commit-config.yaml +0 -0
  18. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/LICENSE +0 -0
  19. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/MANIFEST.in +0 -0
  20. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/django_pfx.egg-info/SOURCES.txt +0 -0
  21. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/django_pfx.egg-info/dependency_links.txt +0 -0
  22. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/django_pfx.egg-info/top_level.txt +0 -0
  23. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/Makefile +0 -0
  24. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/conf.py +0 -0
  25. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/api.views.rst +0 -0
  26. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/authentication.md +0 -0
  27. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/doc/source/cookbook.md +0 -0
  28. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/img/pfx.png +0 -0
  29. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/img/pfx.svg +0 -0
  30. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/__init__.py +0 -0
  31. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/__init__.py +0 -0
  32. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/apidoc/__init__.py +0 -0
  33. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/apidoc/parameters.py +0 -0
  34. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/apidoc/schema.py +0 -0
  35. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/apidoc/tags.py +0 -0
  36. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/apps.py +0 -0
  37. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/decorator/__init__.py +0 -0
  38. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/decorator/rest.py +0 -0
  39. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/default_settings.py +0 -0
  40. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/exceptions.py +0 -0
  41. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/fields.py +0 -0
  42. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/http/__init__.py +0 -0
  43. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/http/json_response.py +0 -0
  44. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  45. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +0 -0
  46. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/management/__init__.py +0 -0
  47. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/management/commands/__init__.py +0 -0
  48. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  49. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/middleware/__init__.py +0 -0
  50. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/middleware/authentication.py +0 -0
  51. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/middleware/locale.py +0 -0
  52. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/models/__init__.py +0 -0
  53. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/models/cache_mixins.py +0 -0
  54. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/models/not_null_fields.py +0 -0
  55. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/models/pfx_models.py +0 -0
  56. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  57. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/serializers/__init__.py +0 -0
  58. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/serializers/json.py +0 -0
  59. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/settings.py +0 -0
  60. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/shortcuts.py +0 -0
  61. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/storage/__init__.py +0 -0
  62. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/storage/s3_storage.py +0 -0
  63. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  64. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  65. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  66. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  67. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/test.py +0 -0
  68. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/urls.py +0 -0
  69. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/__init__.py +0 -0
  70. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/fields.py +0 -0
  71. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/filters_views.py +0 -0
  72. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/locale_views.py +0 -0
  73. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  74. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  75. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/groups.py +0 -0
  76. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  77. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  78. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  79. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  80. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  81. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  82. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  83. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  84. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  85. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/subset.py +0 -0
  86. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  87. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  88. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  89. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  90. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  91. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pfx/pfxcore/views/rest_views.py +0 -0
  92. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/pyproject.toml +0 -0
  93. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/requirements.txt +0 -0
  94. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/runtest.py +0 -0
  95. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/setup.py +0 -0
  96. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/__init__.py +0 -0
  97. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/models.py +0 -0
  98. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/settings/__init__.py +0 -0
  99. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/settings/ci.py +0 -0
  100. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/settings/common.py +0 -0
  101. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/settings/dev.py +0 -0
  102. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/settings/dev_custom_example.py +0 -0
  103. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/settings/dev_default.py +0 -0
  104. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/__init__.py +0 -0
  105. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/basic_api_errors.py +0 -0
  106. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/basic_api_test.py +0 -0
  107. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_api_doc.py +0 -0
  108. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_auth_api.py +0 -0
  109. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_cache.py +0 -0
  110. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_fields.py +0 -0
  111. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_filters.py +0 -0
  112. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_locale_api.py +0 -0
  113. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_perm_tests.py +0 -0
  114. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_perms_api.py +0 -0
  115. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_shortcuts.py +0 -0
  116. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_timezone_middleware.py +0 -0
  117. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_tools.py +0 -0
  118. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_user_queryset.py +0 -0
  119. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_view_decorators.py +0 -0
  120. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/tests/test_view_fields.py +0 -0
  121. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/urls.py +0 -0
  122. {django-pfx-1.2.dev107 → django-pfx-1.2.dev110}/tests/views.py +0 -0
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-pfx
3
- Version: 1.2.dev107
4
- Summary: Django PFX is a toolkit to build web APIs dedicated to be used by React progressive web app.
3
+ Version: 1.2.dev110
4
+ Summary: Django PFX is a toolkit to build rest APIs with the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
7
7
  License: BSD-3-Clause
8
- Project-URL: Source, https://gitlab.com/hmartinet/django-pfx
9
- Project-URL: Tracker, https://gitlab.com/hmartinet/django-pfx/-/issues
8
+ Project-URL: Source, https://gitlab.com/pfx4/django-pfx
9
+ Project-URL: Tracker, https://gitlab.com/pfx4/django-pfx/-/issues
10
+ Project-URL: Documentation, https://pfx4.gitlab.io/django-pfx/doc/
10
11
  Classifier: Environment :: Web Environment
11
12
  Classifier: Framework :: Django
12
13
  Classifier: Framework :: Django :: 3.2
@@ -31,11 +32,8 @@ License-File: LICENSE
31
32
 
32
33
  ![logo]
33
34
 
34
- Django PFX is a toolkit to build web APIs dedicated to be used by React progressive web app.
35
+ Django PFX is a toolkit to build rest APIs with the Django framework.
35
36
 
36
- > **WARNING**
37
- >
38
- > This is an experimental projet. It should not be used in real project because it is incomplete and there is no warranty of keeping compatibility in future version.
39
37
 
40
38
  [logo]: https://gitlab.com/hmartinet/django-pfx/-/raw/master/img/pfx.png "PFX"
41
39
  [pipeline]: https://gitlab.com/hmartinet/django-pfx/badges/master/pipeline.svg "Pipeline Status"
@@ -5,11 +5,8 @@
5
5
 
6
6
  ![logo]
7
7
 
8
- Django PFX is a toolkit to build web APIs dedicated to be used by React progressive web app.
8
+ Django PFX is a toolkit to build rest APIs with the Django framework.
9
9
 
10
- > **WARNING**
11
- >
12
- > This is an experimental projet. It should not be used in real project because it is incomplete and there is no warranty of keeping compatibility in future version.
13
10
 
14
11
  [logo]: https://gitlab.com/hmartinet/django-pfx/-/raw/master/img/pfx.png "PFX"
15
12
  [pipeline]: https://gitlab.com/hmartinet/django-pfx/badges/master/pipeline.svg "Pipeline Status"
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-pfx
3
- Version: 1.2.dev107
4
- Summary: Django PFX is a toolkit to build web APIs dedicated to be used by React progressive web app.
3
+ Version: 1.2.dev110
4
+ Summary: Django PFX is a toolkit to build rest APIs with the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
7
7
  License: BSD-3-Clause
8
- Project-URL: Source, https://gitlab.com/hmartinet/django-pfx
9
- Project-URL: Tracker, https://gitlab.com/hmartinet/django-pfx/-/issues
8
+ Project-URL: Source, https://gitlab.com/pfx4/django-pfx
9
+ Project-URL: Tracker, https://gitlab.com/pfx4/django-pfx/-/issues
10
+ Project-URL: Documentation, https://pfx4.gitlab.io/django-pfx/doc/
10
11
  Classifier: Environment :: Web Environment
11
12
  Classifier: Framework :: Django
12
13
  Classifier: Framework :: Django :: 3.2
@@ -31,11 +32,8 @@ License-File: LICENSE
31
32
 
32
33
  ![logo]
33
34
 
34
- Django PFX is a toolkit to build web APIs dedicated to be used by React progressive web app.
35
+ Django PFX is a toolkit to build rest APIs with the Django framework.
35
36
 
36
- > **WARNING**
37
- >
38
- > This is an experimental projet. It should not be used in real project because it is incomplete and there is no warranty of keeping compatibility in future version.
39
37
 
40
38
  [logo]: https://gitlab.com/hmartinet/django-pfx/-/raw/master/img/pfx.png "PFX"
41
39
  [pipeline]: https://gitlab.com/hmartinet/django-pfx/badges/master/pipeline.svg "Pipeline Status"
@@ -1,4 +1,4 @@
1
- django<4.0,>=3.2
1
+ django<5.0,>=3.2
2
2
  django-cors-headers
3
3
  django_json_widget
4
4
  pyjwt>=2.1
@@ -6,13 +6,7 @@
6
6
  Welcome to Django PFX's documentation!
7
7
  ======================================
8
8
 
9
- Django PFX is a toolkit to build web APIs dedicated
10
- to be used by React progressive web app.
11
-
12
- .. warning::
13
- This is a project in development.
14
- It should not be used in real project because it is incomplete
15
- and changes may break the compatibility in future version.
9
+ Django PFX is a toolkit to build rest APIs with the Django framework.
16
10
 
17
11
 
18
12
  Topics
@@ -1,7 +1,9 @@
1
1
  # View decorator and URL
2
2
  ## @rest_view
3
3
  Used to provide the base path of a view class
4
- ```
4
+ ```python
5
+ from pfx.pfxcore.decorator import rest_view
6
+
5
7
  @rest_view("/base-path")
6
8
  class ViewClass():
7
9
  ```
@@ -9,13 +11,18 @@ class ViewClass():
9
11
  ## @rest_api
10
12
  Used to annotate the rest services method.
11
13
  Parameters are the path and the HTTP method.
12
- ```
14
+ ```python
15
+ from pfx.pfxcore.decorator import rest_api
16
+
13
17
  @rest_api("/path", method="get")
14
18
  def class_method(self):
15
19
  ```
16
20
 
17
21
  A short example
18
- ```
22
+ ```python
23
+ from pfx.pfxcore.decorator import rest_view, rest_api
24
+ from pfx.pfxcore.http import JsonResponse
25
+
19
26
  @rest_view("/books")
20
27
  class BookRestView():
21
28
 
@@ -27,7 +34,9 @@ class BookRestView():
27
34
 
28
35
  ### path parameters
29
36
  Path can contain parameters that are passed to the method.
30
- ```
37
+ ```python
38
+ from pfx.pfxcore.decorator import rest_api
39
+
31
40
  @rest_api("/path/<int:pk>/test/<slug:slug>", method="get")
32
41
  def class_method(self, pk, slug):
33
42
  ```
@@ -35,7 +44,8 @@ def class_method(self, pk, slug):
35
44
  ## Registering urls
36
45
  To be available, annotated view class must be registered
37
46
  in your urls.py file as follows.
38
- ```
47
+
48
+ ```python
39
49
  from pfx.pfxcore import register_views
40
50
 
41
51
  from . import views
@@ -44,9 +54,11 @@ urlpatterns = register_views(
44
54
  views.AuthorRestView,
45
55
  views.BookRestView)
46
56
  ```
57
+
47
58
  You can include multiple views under one path, or add a path
48
59
  wih a specific class method for each HTTP methods:
49
- ```
60
+ ```python
61
+ from django.urls import include, path
50
62
  from pfx.pfxcore import register_views
51
63
 
52
64
  from . import views
@@ -0,0 +1,179 @@
1
+ # Getting Started with PFX
2
+
3
+ ## Install django pfx
4
+
5
+ Using pip
6
+ ```bash
7
+ pip install django-pfx
8
+ ```
9
+
10
+ ## Configuration
11
+
12
+ Add pfxcore to the installed app
13
+
14
+ ```python
15
+ INSTALLED_APPS = [
16
+ 'pfx.pfxcore',
17
+ ]
18
+ ```
19
+
20
+ ## Create your services
21
+
22
+ ### Model class
23
+ Create a simple model class.
24
+ ```python
25
+ from django.db import models
26
+
27
+
28
+ class Book(models.Model):
29
+ BOOK_TYPES = [
30
+ ('science_fiction', 'Science Fiction'),
31
+ ('heroic_fantasy', 'Heroic Fantasy'),
32
+ ('detective', 'Detective')]
33
+
34
+ title = models.CharField("Title", max_length=30)
35
+ author = models.CharField("Author", max_length=150)
36
+ type = models.CharField("Type", max_length=20, choices=BOOK_TYPES)
37
+ pub_date = models.DateField("Pub Date")
38
+ created_at = models.DateField("Created at", auto_now_add=True)
39
+
40
+ class Meta:
41
+ verbose_name = "Book"
42
+ verbose_name_plural = "Books"
43
+
44
+ def __str__(self):
45
+ return f"{self.name}"
46
+
47
+ ```
48
+
49
+ ### Views
50
+ Create a new view
51
+ ```python
52
+ from pfx.pfxcore.decorator import rest_view
53
+ from pfx.pfxcore.views import RestView
54
+
55
+ from book.models import Book
56
+
57
+
58
+ @rest_view("/books")
59
+ class BookRestView(RestView):
60
+ default_public = True
61
+ queryset = Book.objects
62
+ fields = ['title', 'author', 'type', 'pub_date', 'created_at']
63
+ ```
64
+
65
+ ### URLs
66
+ Register the url in urls.py.
67
+ ```python
68
+ from django.urls import path, include
69
+ from pfx.pfxcore import register_views
70
+
71
+
72
+ from book import views
73
+
74
+ apipatterns = register_views(views.BookRestView)
75
+
76
+ urlpatterns = [
77
+ path('api/', include(apipatterns)),
78
+ ]
79
+ ```
80
+
81
+ You now have a fully functional public API for the book objet.
82
+
83
+ ### Test the API
84
+ The next step is to create a test class to test your new API.
85
+ PFX provides [some tools](testing.md) to ease the testing.
86
+
87
+ ```python
88
+ from datetime import date
89
+ from django.test import TransactionTestCase
90
+ from pfx.pfxcore.test import TestAssertMixin, APIClient
91
+
92
+ from book.models import Book, Author
93
+
94
+ class BookTestClass(TestAssertMixin, TransactionTestCase):
95
+
96
+ @classmethod
97
+ def setUpTestData(cls):
98
+ # create some test data
99
+ cls.author = Author.objects.create(
100
+ first_name='Isaac',
101
+ last_name='Asimov')
102
+ cls.book1 = Book.objects.create(
103
+ author=cls.author,
104
+ title="The Caves of Steel",
105
+ type='science_fiction',
106
+ pub_date=date(1954, 1, 1))
107
+ cls.book2 = Book.objects.create(
108
+ author=cls.author,
109
+ title="The Naked Sun",
110
+ type='science_fiction',
111
+ pub_date=date(1957, 1, 1))
112
+
113
+ def test_get_book_list(self):
114
+ client = APIClient()
115
+ response = client.get('/api/books')
116
+
117
+ # assert response status is 200 OK
118
+ self.assertRC(response, 200)
119
+ # assert number of item returned
120
+ self.assertSize(response, 'items', 2)
121
+ # test the author of the second item is Asimov
122
+ self.assertJE(response, 'items.@1.author.pk', self.author.pk)
123
+
124
+ def test_get_book(self):
125
+ client = APIClient()
126
+ response = client.get(f'/api/books/{self.book2.pk}')
127
+
128
+ # assert response status is 200 OK
129
+ self.assertRC(response, 200)
130
+ # assert json content of the response
131
+ self.assertJE(response, 'title', "The Naked Sun")
132
+ self.assertJE(response, 'pub_date', "1957-01-01")
133
+
134
+ def test_create_book(self):
135
+ client = APIClient()
136
+ response = client.post(
137
+ '/api/books/',dict(
138
+ title="The Robots of Dawn",
139
+ author=self.author,
140
+ type='science_fiction',
141
+ pub_date=date(1983, 1, 1)
142
+ ))
143
+ self.assertRC(response, 200)
144
+ self.assertJE(response, 'title', "The Robots of Dawn")
145
+
146
+ def test_create_book_validation(self):
147
+ client = APIClient()
148
+ # make a post request
149
+ response = client.post(
150
+ '/api/books/',dict(
151
+ title=None,
152
+ author=self.author,
153
+ type='science_fiction',
154
+ pub_date=date(1983, 1, 1)
155
+ ))
156
+ self.assertRC(response, 422)
157
+ self.assertJE(
158
+ response, 'title.@0', "This field cannot be null.")
159
+
160
+ def test_update_book(self):
161
+ client = APIClient()
162
+ response = client.put(
163
+ f'/api/books/{self.book2.pk}',dict(
164
+ title="The Robots of Dawn",
165
+ pub_date=date(1983, 1, 1),
166
+ ))
167
+ self.assertRC(response, 200)
168
+ self.assertJE(response, 'title', "The Robots of Dawn")
169
+
170
+ def test_delete_book(self):
171
+ client = APIClient()
172
+ response = client.delete(
173
+ f'/api/books/{self.book2.pk}')
174
+ self.assertRC(response, 200)
175
+
176
+ books = Book.objects.filter(pk=self.book2.pk)
177
+ self.assertEqual(books.count(), 0)
178
+
179
+ ```
@@ -12,7 +12,7 @@ In Django, `USE_I18N` must be `True` to use internationalization. Use `LANGUAGE_
12
12
  You can optionally set `USE_L10N` to `True` (see Django documentation).
13
13
 
14
14
  In Addition, you can set the list of available languages for web services with `LANGUAGES`:
15
- ```
15
+ ```python
16
16
  LANGUAGES = [
17
17
  ('fr', "French"),
18
18
  ('en', "English"),
@@ -5,15 +5,19 @@ Django PFX use plain Django Models classes.
5
5
  This library only provides some helpers for properties
6
6
  and foreign keys representations.
7
7
 
8
- ## `@rest_property`
8
+ ## @rest_property
9
9
  If you want to use properties in your model,
10
- you have to annotate them with @rest_property.
10
+ you have to annotate them with `@rest_property`.
11
11
 
12
12
  Rest property takes 2 parameters, a name and
13
13
  the type of the Field (CharField, IntegerField, etc.)
14
14
 
15
15
  Rest properties can be listed as fields to be returned in list and detail views.
16
- ```
16
+
17
+ ```python
18
+ from django.db import models
19
+ from pfx.pfxcore.decorator import rest_property
20
+
17
21
  class Book(models.Model):
18
22
  name = models.CharField("Name", max_length=30)
19
23
  author = models.ForeignKey(
@@ -35,12 +39,11 @@ class Book(models.Model):
35
39
  ```
36
40
 
37
41
  ## JSONReprMixin
38
-
39
- Foreign keys are returned by {doc}`Django PFX views <pfx_views>` as a JSON
42
+ Foreign keys are returned by [Django PFX views <pfx_views>](./pfx_views.md) as a JSON
40
43
  structure with two fields : pk, resource_name
41
44
 
42
45
  For instance for the book class, with the author foreign key :
43
- ```
46
+ ```python
44
47
  {
45
48
  "author": {
46
49
  "pk": 1,
@@ -60,8 +63,11 @@ by inheriting JSONReprMixin on the Model class and
60
63
  by overriding the json_repr method.
61
64
 
62
65
  For instance for the Author class :
63
- ```
64
- class Author(models.Model):
66
+ ```python
67
+ from django.db import models
68
+ from pfx.pfxcore.models import JSONReprMixin
69
+
70
+ class Author(JSONReprMixin, models.Model):
65
71
  first_name = models.CharField("First Name", max_length=30)
66
72
  last_name = models.CharField("Last Name", max_length=30)
67
73
  slug = models.SlugField("Slug", unique=True)
@@ -80,11 +86,11 @@ class Author(models.Model):
80
86
  ```
81
87
 
82
88
  Which give the following result on the book service :
83
- ```
89
+ ```python
84
90
  {
85
91
  "author": {
86
92
  "pk": 1,
87
- "resource_name": "John Ronald Reuel Tolkien"
93
+ "resource_name": "John Ronald Reuel Tolkien",
88
94
  "resource_slug": "john-ronald-reuel-tolkien"
89
95
  },
90
96
  "created_at": "2022-01-14",
@@ -104,9 +110,11 @@ converting `null` values to empty strings, you can use the following model field
104
110
  * `NotNullCharField`
105
111
  * `NotNullTextField`
106
112
  * `NotNullURLField`
107
- ```
108
- a_string_field = NotNullCharField(
109
- _("A string"), max_length=255, blank=True, default="")
113
+ ```python
114
+ from pfx.pfxcore.models import NotNullCharField
115
+
116
+ a_string_field = NotNullCharField(
117
+ "A string", max_length=255, blank=True, default="")
110
118
  ```
111
119
 
112
120
  The `null` parameter of these fields is automatically set to `False`.
@@ -10,7 +10,9 @@ Provide a get detail service for a model class.
10
10
 
11
11
  By default, all model fields are included in response. You can customize
12
12
  the response by specifying the fields attribute (see [Define Fields](pfx_views.md#define-fields) for details).
13
- ```
13
+
14
+ ```python
15
+ from pfx.pfxcore.decorator import rest_view
14
16
  from pfx.pfxcore.views import BaseRestView, DetailRestViewMixin
15
17
 
16
18
  @rest_view("/books")
@@ -24,7 +26,8 @@ Provide a get detail service for a model class with a slug.
24
26
  Slug field is searched in the `slug` field of the model by default,
25
27
  but it can be overridden with the `SLUG_FIELD` attribute.
26
28
 
27
- ```
29
+ ```python
30
+ from pfx.pfxcore.decorator import rest_view
28
31
  from pfx.pfxcore.views import BaseRestView, SlugDetailRestViewMixin
29
32
 
30
33
  @rest_view("/authors")
@@ -33,13 +36,15 @@ class AuthorRestView(SlugDetailRestViewMixin, BaseRestView):
33
36
  SLUG_FIELD = "slug"
34
37
  fields = ['name', 'slug', 'created_at', 'type']
35
38
  ```
39
+
36
40
  ## ListRestViewMixin
37
41
  Provide a list service for a model class.
38
42
 
39
43
  By default, list fields are taken from fields attributes.
40
44
  They can also be listed in the list_fields attribute if you need to have
41
45
  different fields in the list than in other views.
42
- ```
46
+ ```python
47
+ from pfx.pfxcore.decorator import rest_view
43
48
  from pfx.pfxcore.views import BaseRestView, ListRestViewMixin
44
49
 
45
50
  @rest_view("/books")
@@ -47,11 +52,12 @@ class BookRestView(ListRestViewMixin, BaseRestView):
47
52
  queryset = Book.objects
48
53
  list_fields = ['name', 'author', 'pub_date', 'created_at', 'type']
49
54
  ```
55
+
50
56
  ### Pagination
51
57
  If you pass `?subset=pagination`, the response will include pagination data in meta:
52
- ```
58
+ ```python
53
59
  {
54
- "items": […],
60
+ "items": [''],
55
61
  "meta": {
56
62
  "page": 1,
57
63
  "page_size": 10,
@@ -66,9 +72,9 @@ The page_size cannot be greater than `PFX_MAX_LIST_RESULT_SIZE` settings.
66
72
  Override `pagination_result(self, qs)` to customize the behavior.
67
73
 
68
74
  If you pass `?subset=offset`, the response will include offset/limit data in meta:
69
- ```
75
+ ```python
70
76
  {
71
- "items": […],
77
+ "items": [''],
72
78
  "meta": {
73
79
  "count": 200,
74
80
  "page_count": 20,
@@ -79,24 +85,26 @@ If you pass `?subset=offset`, the response will include offset/limit data in met
79
85
  ```
80
86
  The limit cannot be greater than `PFX_MAX_LIST_RESULT_SIZE` settings.
81
87
  Override `offset_result(self, qs)` to customize the behavior.
88
+
82
89
  ### Filters
83
90
  List view can have filters.
91
+
84
92
  #### ModelFilter
85
- Use `ModelFilter` to add a filter on a ORM field:
86
- ```
93
+ Use `ModelFilter` to add a filter on an ORM field:
94
+ ```python
87
95
  from pfx.pfxcore.views import (
88
96
  RestView,
89
97
  ModelFilter)
90
98
 
91
-
92
99
  class AuthorRestView(RestView):
93
100
  filters = [
94
101
  ModelFilter(Author, 'name'),
95
102
  ]
96
103
  ```
104
+
97
105
  #### Filter
98
106
  Use `Filter` to add a custom filter:
99
- ```
107
+ ```python
100
108
  from django.db.models import Q
101
109
 
102
110
  from pfx.pfxcore.views import (
@@ -111,12 +119,14 @@ def name_filter(value):
111
119
 
112
120
  class AuthorRestView(RestView):
113
121
  filters = [
114
- Filter('name', _("Name"), FieldType.CharField, name_filter),
122
+ Filter('name', "Name", FieldType.CharField, name_filter),
115
123
  ]
116
124
  ```
125
+
117
126
  ## CreateRestViewMixin
118
127
  Provide a creation service for a model class.
119
- ```
128
+ ```python
129
+ from pfx.pfxcore.decorator import rest_view
120
130
  from pfx.pfxcore.views import BaseRestView, CreateRestViewMixin
121
131
 
122
132
  @rest_view("/books")
@@ -124,11 +134,15 @@ class BookRestView(CreateRestViewMixin, BaseRestView):
124
134
  queryset = Book.objects
125
135
  fields = ['name', 'author', 'pub_date', 'created_at', 'type']
126
136
  ```
137
+
127
138
  ### Default values
128
139
  You can set default values for fields in the ORM object field. But if
129
140
  you need to set it at view level, you can use the `default_values`
130
141
  class attribute.
131
- ```
142
+ ```python
143
+ from pfx.pfxcore.decorator import rest_view
144
+ from pfx.pfxcore.views import BaseRestView, CreateRestViewMixin
145
+
132
146
  @rest_view("/books")
133
147
  class BookRestView(CreateRestViewMixin, BaseRestView):
134
148
  queryset = Book.objects
@@ -137,14 +151,15 @@ class BookRestView(CreateRestViewMixin, BaseRestView):
137
151
  )
138
152
  ```
139
153
  If you need to set dynamics default values,
140
- you can override following methods (depending of your needs):
154
+ you can override following methods (depending on your needs):
141
155
  * `get_default_values(self)`: return `default_values`.
142
156
  * `new_object(self)`: return a new object instance with `get_default_values()`.
143
157
  * `is_valid(self, obj, created=False, rel_data=None)`: persist the instance after validation.
144
158
 
145
159
  ## UpdateRestViewMixin
146
160
  Provide an update service for a model class.
147
- ```
161
+ ```python
162
+ from pfx.pfxcore.decorator import rest_view
148
163
  from pfx.pfxcore.views import BaseRestView, UpdateRestViewMixin
149
164
 
150
165
  @rest_view("/books")
@@ -155,7 +170,8 @@ class BookRestView(UpdateRestViewMixin, BaseRestView):
155
170
 
156
171
  ## DeleteRestViewMixin
157
172
  Provide a delete service for a model class.
158
- ```
173
+ ```python
174
+ from pfx.pfxcore.decorator import rest_view
159
175
  from pfx.pfxcore.views import BaseRestView, DeleteRestViewMixin
160
176
 
161
177
  @rest_view("/books")
@@ -175,22 +191,30 @@ system from scratch id to inherit Django original `View` instead.
175
191
  ### Default behavior
176
192
  By default, all methods are private. You can modify
177
193
  the `default_public` attribute to change this.
178
- ```
194
+ ```python
195
+ from pfx.pfxcore.decorator import rest_view
196
+ from pfx.pfxcore.views import RestView
197
+
179
198
  @rest_view("/books")
180
199
  class BookRestView(RestView):
181
200
  queryset = Book.objects
182
201
  default_public = True
183
202
  ```
203
+
184
204
  ### Public method
185
205
  If you want to define specific methods as a public methods,
186
206
  add corresponding attributes `${method_name}_public`:
187
- ```
207
+ ```python
208
+ from pfx.pfxcore.decorator import rest_view
209
+ from pfx.pfxcore.views import RestView
210
+
188
211
  @rest_view("/books")
189
212
  class BookRestView(RestView):
190
213
  queryset = Book.objects
191
214
  get_public = True
192
215
  get_list_public = True
193
216
  ```
217
+
194
218
  ### Check user access
195
219
  For private methods, you can verify user access in two steps:
196
220
  * By overriding the `perm(self)` method.
@@ -201,14 +225,18 @@ If it returns `true` (default behavior), access is allowed
201
225
  if `${method_name}_perm(self)` method does not exists.
202
226
  If `${method_name}_perm` exists, it is called and must
203
227
  return `true` to allow access.
204
- ```
228
+ ```python
229
+ from pfx.pfxcore.decorator import rest_view
230
+ from pfx.pfxcore.views import RestView
231
+
205
232
  @rest_view("/books")
206
233
  class BookRestView(RestView):
207
234
  queryset = Book.objects
208
235
 
209
- def my_method_perm(self)
236
+ def my_method_perm(self):
210
237
  return self.request.user.is_admin
211
238
  ```
239
+
212
240
  ### Check user access based on data
213
241
  You can check user access based on data by overriding following methods:
214
242
  * `object_create_perm(self, data)`