Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs/start/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ The following debugging / logging options are available:
| INVENTREE_JSON_LOG | json_log | log as json | False |
| INVENTREE_WRITE_LOG | write_log | Enable writing of log messages to file at config base | False |
| INVENTREE_CONSOLE_LOG | console_log | Enable logging to console | True |
| INVENTREE_SCHEMA_LEVEL | schema.level | Set level of added schema extensions detail (0-3) 0 = including no additional detail | 0 |

### Debug Mode

Expand Down
5 changes: 4 additions & 1 deletion src/backend/InvenTree/InvenTree/api_version.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
"""InvenTree API version information."""

# InvenTree API version
INVENTREE_API_VERSION = 423
INVENTREE_API_VERSION = 424
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""

INVENTREE_API_TEXT = """

v424 -> 2025-11-06 : https://github.com/inventree/InvenTree/pull/10628
- Extend schema generation to include inventree vendor fields

v423 -> 2025-11-05 : https://github.com/inventree/InvenTree/pull/10772
- Adds "category_detail" field to BomItem API endpoints
- Adds "category_detail" field to BuildLine API endpoints
Expand Down
57 changes: 53 additions & 4 deletions src/backend/InvenTree/InvenTree/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,20 @@ def get_operation(
operation['requestBody'] = request_body
self.method = original_method

parameters = operation.get('parameters', [])

# If pagination limit is not set (default state) then all results will return unpaginated. This doesn't match
# what the schema defines to be the expected result. This forces limit to be present, producing the expected
# type.
pagination_class = getattr(self.view, 'pagination_class', None)
if pagination_class and pagination_class == LimitOffsetPagination:
parameters = operation.get('parameters', [])
for parameter in parameters:
if parameter['name'] == 'limit':
parameter['required'] = True

# Add valid order selections to the ordering field description.
ordering_fields = getattr(self.view, 'ordering_fields', None)
if ordering_fields is not None:
parameters = operation.get('parameters', [])
for parameter in parameters:
if parameter['name'] == 'ordering':
schema_order = []
Expand All @@ -117,8 +117,6 @@ def get_operation(
if search_fields is not None:
# Ensure consistent ordering of search fields
search_fields = sorted(search_fields)

parameters = operation.get('parameters', [])
for parameter in parameters:
if parameter['name'] == 'search':
parameter['description'] = (
Expand All @@ -135,8 +133,59 @@ def get_operation(
schema['items'] = {'$ref': schema['$ref']}
del schema['$ref']

# Add vendor extensions for custom behavior
operation.update(self.get_inventree_extensions())

return operation

def get_inventree_extensions(self):
"""Add InvenTree specific extensions to the schema."""
from rest_framework.generics import RetrieveAPIView
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin

# from rest_framework.generics import ListAPIView
# from rest_framework.mixins import CreateModelMixin,ListModelMixin,
from data_exporter.mixins import DataExportViewMixin
from InvenTree.api import BulkOperationMixin
from InvenTree.mixins import CleanMixin

lvl = settings.SCHEMA_VENDOREXTENSION_LEVEL
"""Level of detail for InvenTree extensions."""

if lvl == 0:
return {}

mro = self.view.__class__.__mro__

data = {}
if lvl >= 1:
data['x-inventree-meta'] = {
'version': '1.0',
'is_detail': any(
a in mro
for a in [RetrieveModelMixin, UpdateModelMixin, RetrieveAPIView]
),
'is_bulk': BulkOperationMixin in mro,
'is_cleaned': CleanMixin in mro,
'is_filtered': hasattr(self.view, 'output_options'),
'is_exported': DataExportViewMixin in mro,
}
if lvl >= 2:
data['x-inventree-components'] = [str(a) for a in mro]
try:
qs = self.view.get_queryset()
qs = qs.model if qs is not None and hasattr(qs, 'model') else None
except Exception:
qs = None

data['x-inventree-model'] = {
'scope': 'core',
'model': str(qs.__name__) if qs else None,
'app': str(qs._meta.app_label) if qs else None,
}

return data


def postprocess_required_nullable(result, generator, request, public):
"""Un-require nullable fields.
Expand Down
3 changes: 3 additions & 0 deletions src/backend/InvenTree/InvenTree/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -1480,6 +1480,9 @@

# Configuration for API schema generation / oAuth2
SPECTACULAR_SETTINGS = spectacular.get_spectacular_settings()
SCHEMA_VENDOREXTENSION_LEVEL = get_setting(
'INVENTREE_SCHEMA_LEVEL', 'schema.level', default_value=0, typecast=int
)

OAUTH2_PROVIDER = {
# default scopes
Expand Down
4 changes: 4 additions & 0 deletions src/backend/InvenTree/config_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ debug: False
debug_querycount: False
debug_shell: False

# Schema generation options
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is the default value, please comment it out in the config_template.yaml file - that way, if we ever change the default, we won't have users who are "locked in" to the old default

schema:
level: 0 # Level of added schema extensions detail (0-3) 0 = including no additional detail, or use the environment variable INVENTREE_SCHEMA_LEVEL

# Set to False to disable the admin interface, or use the environment variable INVENTREE_ADMIN_ENABLED
#admin_enabled: True

Expand Down
Loading