django-ninja-aio-crud 2.12.0__tar.gz → 2.12.2__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.

Potentially problematic release.


This version of django-ninja-aio-crud might be problematic. Click here for more details.

Files changed (103) hide show
  1. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/.github/workflows/docs.yml +2 -0
  2. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/PKG-INFO +1 -1
  3. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/__init__.py +1 -1
  4. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/helpers/query.py +6 -1
  5. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/models/serializers.py +4 -4
  6. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_query_util.py +54 -0
  7. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/.github/dependabot.yml +0 -0
  8. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/.github/workflows/coverage.yml +0 -0
  9. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/.github/workflows/publish.yml +0 -0
  10. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/.gitignore +0 -0
  11. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/.pre-commit-config.yaml +0 -0
  12. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/LICENSE +0 -0
  13. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/README.md +0 -0
  14. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/CNAME +0 -0
  15. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/authentication.md +0 -0
  16. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/models/model_serializer.md +0 -0
  17. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/models/model_util.md +0 -0
  18. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/models/serializers.md +0 -0
  19. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/pagination.md +0 -0
  20. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/renderers/orjson_renderer.md +0 -0
  21. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/views/api_view.md +0 -0
  22. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/views/api_view_set.md +0 -0
  23. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/views/decorators.md +0 -0
  24. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/api/views/mixins.md +0 -0
  25. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/auth.md +0 -0
  26. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/contributing.md +0 -0
  27. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/extra.css +0 -0
  28. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/images/index/foo-index-create-swagger.png +0 -0
  29. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/images/index/foo-index-delete-swagger.png +0 -0
  30. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/images/index/foo-index-list-swagger.png +0 -0
  31. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/images/index/foo-index-retrieve-swagger.png +0 -0
  32. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/images/index/foo-index-swagger.png +0 -0
  33. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/images/index/foo-index-update-swagger.png +0 -0
  34. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/installation.md +0 -0
  35. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/getting_started/quick_start.md +0 -0
  36. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/images/bar-swagger.png +0 -0
  37. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/images/favicon.ico +0 -0
  38. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/images/foo-swagger.png +0 -0
  39. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/images/logo.png +0 -0
  40. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/images/model_util/foo-reverse-relations-swagger.png +0 -0
  41. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/index.md +0 -0
  42. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/release_notes.md +0 -0
  43. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/requirements.txt +0 -0
  44. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/tutorial/authentication.md +0 -0
  45. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/tutorial/crud.md +0 -0
  46. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/tutorial/filtering.md +0 -0
  47. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/docs/tutorial/model.md +0 -0
  48. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/main.py +0 -0
  49. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/mkdocs.yml +0 -0
  50. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/api.py +0 -0
  51. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/auth.py +0 -0
  52. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/decorators/__init__.py +0 -0
  53. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/decorators/operations.py +0 -0
  54. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/decorators/views.py +0 -0
  55. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/exceptions.py +0 -0
  56. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/factory/__init__.py +0 -0
  57. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/factory/operations.py +0 -0
  58. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/helpers/__init__.py +0 -0
  59. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/helpers/api.py +0 -0
  60. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/models/__init__.py +0 -0
  61. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/models/utils.py +0 -0
  62. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/parsers.py +0 -0
  63. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/renders.py +0 -0
  64. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/schemas/__init__.py +0 -0
  65. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/schemas/api.py +0 -0
  66. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/schemas/filters.py +0 -0
  67. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/schemas/generics.py +0 -0
  68. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/schemas/helpers.py +0 -0
  69. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/types.py +0 -0
  70. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/views/__init__.py +0 -0
  71. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/views/api.py +0 -0
  72. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/ninja_aio/views/mixins.py +0 -0
  73. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/pyproject.toml +0 -0
  74. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/requirements.dev.txt +0 -0
  75. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/run-local-coverage.sh +0 -0
  76. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/__init__.py +0 -0
  77. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/core/__init__.py +0 -0
  78. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/core/test_decorators.py +0 -0
  79. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/core/test_exceptions_api.py +0 -0
  80. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/core/test_renderer_parser.py +0 -0
  81. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/generics/__init__.py +0 -0
  82. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/generics/literals.py +0 -0
  83. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/generics/models.py +0 -0
  84. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/generics/request.py +0 -0
  85. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/generics/views.py +0 -0
  86. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/helpers/__init__.py +0 -0
  87. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/helpers/test_many_to_many_api.py +0 -0
  88. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/models/__init__.py +0 -0
  89. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/models/test_model_util.py +0 -0
  90. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/models/test_models_extra.py +0 -0
  91. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_app/__init__.py +0 -0
  92. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_app/models.py +0 -0
  93. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_app/schema.py +0 -0
  94. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_app/serializers.py +0 -0
  95. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_app/views.py +0 -0
  96. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_auth.py +0 -0
  97. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_decorators.py +0 -0
  98. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_exceptions.py +0 -0
  99. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_serializers.py +0 -0
  100. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/test_settings.py +0 -0
  101. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/views/__init__.py +0 -0
  102. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/views/test_views.py +0 -0
  103. {django_ninja_aio_crud-2.12.0 → django_ninja_aio_crud-2.12.2}/tests/views/test_viewset.py +0 -0
@@ -24,6 +24,7 @@ on:
24
24
  - "2.9"
25
25
  - "2.10"
26
26
  - "2.11"
27
+ - "2.12"
27
28
  make_latest:
28
29
  description: 'Set as "latest" and default?'
29
30
  type: boolean
@@ -51,6 +52,7 @@ on:
51
52
  - "2.9"
52
53
  - "2.10"
53
54
  - "2.11"
55
+ - "2.12"
54
56
  delete_confirm:
55
57
  description: 'Confirm deletion of the selected version'
56
58
  type: boolean
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-ninja-aio-crud
3
- Version: 2.12.0
3
+ Version: 2.12.2
4
4
  Summary: Django Ninja AIO CRUD - Rest Framework
5
5
  Author: Giuseppe Casillo
6
6
  Requires-Python: >=3.10, <3.15
@@ -1,6 +1,6 @@
1
1
  """Django Ninja AIO CRUD - Rest Framework"""
2
2
 
3
- __version__ = "2.12.0"
3
+ __version__ = "2.12.2"
4
4
 
5
5
  from .api import NinjaAIO
6
6
 
@@ -78,6 +78,11 @@ class QueryUtil:
78
78
  self.detail_config: ModelQuerySetSchema = self._configs.get(
79
79
  self.SCOPES.DETAIL, ModelQuerySetSchema()
80
80
  )
81
+ # Fallback detail config to read config if not explicitly set
82
+ if not self.detail_config.select_related:
83
+ self.detail_config.select_related = self.read_config.select_related.copy()
84
+ if not self.detail_config.prefetch_related:
85
+ self.detail_config.prefetch_related = self.read_config.prefetch_related.copy()
81
86
 
82
87
  def _get_config(self, conf_name: str) -> ModelQuerySetSchema:
83
88
  """Helper method to retrieve configuration attributes."""
@@ -103,7 +108,7 @@ class QueryUtil:
103
108
  raise ValueError(
104
109
  f"Invalid scope '{scope}' for QueryUtil. Supported scopes: {valid_scopes}"
105
110
  )
106
- config = self._configs.get(scope, ModelQuerySetSchema())
111
+ config: ModelQuerySetSchema = self._configs.get(scope, ModelQuerySetSchema())
107
112
  if config.select_related:
108
113
  queryset = queryset.select_related(*config.select_related)
109
114
  if config.prefetch_related:
@@ -424,10 +424,10 @@ class BaseSerializer:
424
424
  @classmethod
425
425
  def _warn_missing_relation_serializer(cls, field_name: str, model) -> None:
426
426
  """Emit warning for reverse relations without explicit serializer mapping."""
427
- if not isinstance(model, ModelSerializerMeta) and (
428
- not getattr(settings, "NINJA_AIO_TESTING", False)
429
- or getattr(settings, "NINJA_AIO_RAISE_SERIALIZATION_WARNINGS", False)
430
- ):
427
+ if (
428
+ not isinstance(model, ModelSerializerMeta)
429
+ and not getattr(settings, "NINJA_AIO_TESTING", False)
430
+ ) or getattr(settings, "NINJA_AIO_RAISE_SERIALIZATION_WARNINGS", False):
431
431
  warnings.warn(
432
432
  f"{cls.__name__}: reverse relation '{field_name}' is listed in read fields "
433
433
  "but has no entry in relations_serializers; it will be auto-resolved only "
@@ -96,6 +96,60 @@ class QueryUtilDedicatedTestCase(TestCase):
96
96
  m_pref.assert_not_called()
97
97
 
98
98
 
99
+ def test_detail_scope_fallback_to_read_select_related(self):
100
+ """Test that DETAIL scope falls back to READ's select_related when not configured."""
101
+ # TestModelSerializerForeignKey has read config but no detail config
102
+ qs = app_models.TestModelSerializerForeignKey.objects.all()
103
+ with mock.patch(
104
+ "django.db.models.query.QuerySet.select_related",
105
+ side_effect=lambda self, *args: self,
106
+ autospec=True,
107
+ ) as m_sel:
108
+ _ = self.query_util_fk.apply_queryset_optimizations(
109
+ qs, self.query_util_fk.SCOPES.DETAIL
110
+ )
111
+ sel_args = m_sel.call_args[0][1:]
112
+ # Should use read_config's select_related as fallback
113
+ self.assertEqual(sel_args, ("test_model_serializer",))
114
+
115
+ def test_detail_scope_fallback_to_read_prefetch_related(self):
116
+ """Test that DETAIL scope falls back to READ's prefetch_related when not configured."""
117
+ # TestModelSerializerManyToMany has queryset_request with prefetch but no detail
118
+ # We need to set up read config with prefetch to test fallback
119
+ qs = app_models.TestModelSerializerManyToMany.objects.all()
120
+ with mock.patch(
121
+ "django.db.models.query.QuerySet.prefetch_related",
122
+ side_effect=lambda self, *args: self,
123
+ autospec=True,
124
+ ) as m_pref:
125
+ _ = self.query_util_m2m.apply_queryset_optimizations(
126
+ qs, self.query_util_m2m.SCOPES.DETAIL
127
+ )
128
+ # M2M model has no read config, so detail should also have empty prefetch
129
+ m_pref.assert_not_called()
130
+
131
+ def test_detail_config_initialized_with_read_fallback(self):
132
+ """Test that detail_config is initialized with read_config values when not set."""
133
+ # FK model has read config with select_related but no detail config
134
+ self.assertEqual(
135
+ self.query_util_fk.detail_config.select_related,
136
+ self.query_util_fk.read_config.select_related,
137
+ )
138
+ self.assertEqual(
139
+ self.query_util_fk.detail_config.prefetch_related,
140
+ self.query_util_fk.read_config.prefetch_related,
141
+ )
142
+
143
+ def test_detail_config_independent_copy(self):
144
+ """Test that detail_config is a copy, not a reference to read_config lists."""
145
+ # Ensure modifying detail_config doesn't affect read_config
146
+ original_read_select = self.query_util_fk.read_config.select_related.copy()
147
+ self.query_util_fk.detail_config.select_related.append("test_field")
148
+ self.assertEqual(
149
+ self.query_util_fk.read_config.select_related, original_read_select
150
+ )
151
+
152
+
99
153
  @tag("scope_namespace")
100
154
  class ScopeNamespaceTestCase(TestCase):
101
155
  """Tests for ScopeNamespace class (covers line 17 - __iter__)."""