diff --git a/CHANGES b/CHANGES index 16ce794f..22f07134 100644 --- a/CHANGES +++ b/CHANGES @@ -4,9 +4,10 @@ Changelog Changes in Flask-Restless-NG ============================ -Unreleased +Version 3.2.0 ------------- - Dropped savalidation support +- Added a parameter to serializer to skip primary key check (not recommended) Version 3.1.0 (2023-10-14): diff --git a/flask_restless/__init__.py b/flask_restless/__init__.py index 6e482231..b02abf93 100644 --- a/flask_restless/__init__.py +++ b/flask_restless/__init__.py @@ -13,7 +13,7 @@ """ #: The current version of this extension. -__version__ = '3.1.0' +__version__ = '3.2.0' # The following names are available as part of the public API for Flask-Restless-NG. diff --git a/flask_restless/manager.py b/flask_restless/manager.py index dd4e9846..154ce7b3 100644 --- a/flask_restless/manager.py +++ b/flask_restless/manager.py @@ -309,6 +309,7 @@ def create_api_blueprint( allow_to_many_replacement: bool = False, allow_delete_from_to_many_relationships: bool = False, allow_client_generated_ids: bool = False, + allow_non_primary_key_id: bool = False, ): """Creates and returns a ReSTful API interface as a blueprint, but does not register it on any :class:`flask.Flask` application. @@ -547,7 +548,8 @@ def create_api_blueprint( # provided. if serializer is None: serializer = DefaultSerializer(model, collection_name, self, primary_key=primary_key, - only=only, exclude=exclude, additional_attributes=additional_attributes) + only=only, exclude=exclude, additional_attributes=additional_attributes, + allow_non_primary_key_id=allow_non_primary_key_id) session = self.session if deserializer is None: diff --git a/flask_restless/serialization.py b/flask_restless/serialization.py index d03272e6..a1ebcfa0 100644 --- a/flask_restless/serialization.py +++ b/flask_restless/serialization.py @@ -330,7 +330,13 @@ def deserialize(self, document): class DefaultSerializer(Serializer): """Default Serializer implementation.""" - def __init__(self, model, type_name, api_manager, primary_key=None, only=None, exclude=None, additional_attributes=None, **kwargs): + def __init__(self, model, type_name, api_manager, + primary_key=None, + only=None, + exclude=None, + additional_attributes=None, + allow_non_primary_key_id=False, + **kwargs): super().__init__(**kwargs) if only is not None and exclude is not None: raise ValueError('Cannot specify both `only` and `exclude` keyword arguments simultaneously') @@ -343,7 +349,7 @@ def __init__(self, model, type_name, api_manager, primary_key=None, only=None, e self._type = type_name pk_names = primary_key_names(model) if primary_key: - if primary_key not in pk_names: + if not allow_non_primary_key_id and primary_key not in pk_names: raise ValueError(f'Column `{primary_key}` is not a primary key') else: raise ValueError('`primary_key` is required') diff --git a/flask_restless/views/base.py b/flask_restless/views/base.py index f9fb76e0..61d9478f 100644 --- a/flask_restless/views/base.py +++ b/flask_restless/views/base.py @@ -595,6 +595,7 @@ def extract_error_messages(exception): if hasattr(exception, 'errors'): return exception.errors + def error(id_=None, links=None, status=None, code=None, title=None, detail=None, source=None, meta=None): """Returns a dictionary representation of an error as described in the diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 16f40204..a8f6994e 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -2,6 +2,7 @@ import enum import json +import pytest from sqlalchemy import Boolean from sqlalchemy import Column from sqlalchemy import Date @@ -86,3 +87,17 @@ def test_serialize_attributes(): 'interval_field': 60.0, 'enum_field': 'two' } + + +def test_raises_value_error_for_empty_pk(): + with pytest.raises(ValueError): + DefaultSerializer(Model, 'test-model', None) + + +def test_raises_value_error_when_provided_pk_is_not_pk(): + with pytest.raises(ValueError): + DefaultSerializer(Model, 'test-model', None, primary_key='date_field') + + +def test_skip_pk_test(): + assert DefaultSerializer(Model, 'test-model', None, primary_key='date_field', allow_non_primary_key_id=True) diff --git a/tests/test_validation.py b/tests/test_validation.py index 6b8603bf..4725b117 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -18,7 +18,6 @@ client. """ -import unittest from sqlalchemy import Column from sqlalchemy import ForeignKey