paperap.models.abstract.model module
Define base model classes for Paperless-ngx API objects.
This module provides the foundation for all model classes in Paperap, implementing core functionality for serialization, validation, and API interactions. The models handle data mapping between Python objects and the Paperless-ngx API, with support for automatic saving, dirty tracking, and asynchronous operations.
The module contains two primary classes: - BaseModel: Abstract base class for all API objects - StandardModel: Extension of BaseModel for objects with ID fields
These classes are designed to be subclassed by specific resource models like Document, Tag, Correspondent, etc.
- class paperap.models.abstract.model.ModelConfigType[source]
Bases:
TypedDict
Define configuration options for Pydantic models.
This type definition specifies the configuration options used for all Pydantic models in the application, ensuring consistent behavior across all model classes.
- populate_by_name
Allow population by field name as well as alias.
- validate_assignment
Validate values when attributes are set.
- validate_default
Validate default values during model initialization.
- use_enum_values
Use enum values rather than enum instances.
- extra
How to handle extra fields (ignore them).
- arbitrary_types_allowed
Allow arbitrary types in model fields.
- class paperap.models.abstract.model.BaseModel(**data)[source]
-
Base model for all Paperless-ngx API objects.
Provide automatic serialization, deserialization, and API interactions with minimal configuration. This abstract class serves as the foundation for all models in the Paperap library, handling data validation, dirty tracking, and API communication.
- _meta
Metadata for the model, including filtering and resource information.
- _save_lock
Lock for saving operations to prevent race conditions.
- _pending_save
Future object for pending save operations.
- _save_executor
Executor for asynchronous save operations.
- _status
Current status of the model (INITIALIZING, READY, UPDATING, SAVING).
- _original_data
Original data from the server for dirty checking.
- _saved_data
Data last sent to the database during save operations.
- _resource
Associated resource for API interactions.
- Raises:
ValueError – If resource is not provided during initialization.
Examples
Models are typically accessed through the client interface:
>>> document = client.documents.get(123) >>> print(document.title) >>> document.title = "New Title" >>> document.save()
- Parameters:
data (
Any
)
- class Meta(model)[source]
Bases:
Generic
Metadata for the Model.
Define model behavior, filtering capabilities, and API interaction rules. Each model class has its own Meta instance that controls how the model interacts with the Paperless-ngx API.
- model
Reference to the model class this metadata belongs to.
- name
The name of the model, used in API paths and error messages.
- read_only_fields
Fields that should not be modified by the client.
- filtering_disabled
Fields that cannot be used for filtering.
- filtering_fields
Fields allowed for filtering operations.
- supported_filtering_params
Specific filter parameters allowed during queryset filtering (e.g., “content__icontains”, “id__gt”).
- blacklist_filtering_params
Filter parameters explicitly disallowed.
- filtering_strategies
Strategies that determine how filtering is handled (ALLOW_ALL, ALLOW_NONE, WHITELIST, BLACKLIST).
- field_map
Map of API field names to model attribute names.
- save_on_write
If True, updating attributes triggers automatic save. If None, follows client.settings.save_on_write.
- save_timeout
Timeout in seconds for save operations.
- Raises:
ValueError – If both ALLOW_ALL and ALLOW_NONE filtering strategies are set, which would create contradictory behavior.
Examples
Defining a custom Meta for a model:
>>> class Document(StandardModel): >>> class Meta(StandardModel.Meta): >>> read_only_fields = {"content", "checksum"} >>> filtering_strategies = {FilteringStrategies.WHITELIST} >>> supported_filtering_params = {"title__icontains", "created__gt"}
- Parameters:
model (type[_Self])
-
filtering_strategies:
ClassVar
[set
[FilteringStrategies
]] = {FilteringStrategies.BLACKLIST}
- filter_allowed(filter_param)[source]
Check if a filter parameter is allowed based on the filtering strategies.
Evaluate whether a given filter parameter can be used with this model based on the configured filtering strategies and rules. This method implements the filtering logic defined by the model’s filtering_strategies.
- Parameters:
filter_param (
str
) – The filter parameter to check (e.g., “title__contains”).- Returns:
True if the filter is allowed, False otherwise.
- Return type:
Examples
>>> meta.filter_allowed("title__contains") True >>> meta.filter_allowed("content__exact") False # If content is in filtering_disabled
- classmethod __init_subclass__(**kwargs)[source]
Initialize subclass and set up metadata.
Ensure that each subclass has its own Meta definition and properly inherits metadata attributes from parent classes. This method handles the automatic creation and configuration of model metadata.
- Parameters:
**kwargs (
Any
) – Additional keyword arguments passed to parent __init_subclass__.- Raises:
ConfigurationError – If no Meta class is found in the class hierarchy.
- Return type:
Notes
This method automatically: - Creates a Meta class for the subclass if not explicitly defined - Inherits and merges metadata from parent classes - Initializes the _meta instance for the subclass
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'populate_by_name': True, 'use_enum_values': True, 'validate_assignment': True, 'validate_default': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- __init__(**data)[source]
Initialize the model with resource and data.
Set up the model with the provided resource and initialize it with field values from the API response or user input.
- Parameters:
**data (
Any
) – Field values to initialize the model with.- Raises:
ValueError – If resource is not provided or properly initialized.
Notes
Models should typically be created through their resource’s methods rather than directly instantiated.
- property resource: BaseResource[Self]
Get the resource associated with this model.
Provide access to the resource instance that handles API interactions for this model type, such as retrieving, creating, updating, and deleting objects.
- Returns:
The resource instance for this model type.
- Return type:
BaseResource[Self]
- property save_executor: ThreadPoolExecutor
Get the thread pool executor for asynchronous save operations.
Provide access to the thread pool that handles asynchronous save operations, creating a new executor if one doesn’t exist yet.
- Returns:
- The executor for handling
asynchronous save operations.
- Return type:
- cleanup()[source]
Clean up resources used by the model.
Shut down the save executor to release resources. Call this method when the model is no longer needed to prevent resource leaks.
- Return type:
- model_post_init(context: Any, /) None
We need to both initialize private attributes and call the user-defined model_post_init method.
- classmethod from_dict(data)[source]
Create a model instance from API response data.
Instantiate a model from a dictionary of API response data, handling field mapping and type conversion through the resource’s parse_to_model method.
- Parameters:
data (
dict
[str
,Any
]) – Dictionary containing the API response data.- Returns:
A model instance initialized with the provided data.
- Return type:
Self
Examples
>>> api_data = {"id": 123, "title": "Invoice", "created": "2023-01-01T00:00:00Z"} >>> doc = Document.from_dict(api_data) >>> print(doc.id, doc.title) 123 Invoice
- to_dict(*, include_read_only=True, exclude_none=False, exclude_unset=True)[source]
Convert the model to a dictionary for API requests.
Prepare the model data for submission to the API, with options to control which fields are included based on their properties and values.
- Parameters:
include_read_only (
bool
) – Whether to include read-only fields in the output. Set to False when preparing data for update operations.exclude_none (
bool
) – Whether to exclude fields with None values.exclude_unset (
bool
) – Whether to exclude fields that were not explicitly set. Useful for partial updates.
- Returns:
A dictionary with model data ready for API submission.
- Return type:
Examples
>>> # Full representation including all fields >>> data = doc.to_dict() >>> >>> # Only include fields that can be modified >>> update_data = doc.to_dict(include_read_only=False) >>> >>> # Only include fields that have been explicitly set >>> partial_data = doc.to_dict(exclude_unset=True)
- dirty_fields(comparison='both')[source]
Show which fields have changed since last update from the Paperless NGX database.
Compare the current model data with the last saved or retrieved data to identify changes. This method helps determine what will be sent to the server on the next save operation.
- Parameters:
comparison (
Literal
['saved'
,'db'
,'both'
]) – Specify the data to compare against: - “saved”: Compare against the last data sent to Paperless NGX - “db”: Compare against the last data retrieved from Paperless NGX - “both”: Compare against both saved and db data (default)- Returns:
- A dictionary mapping field names to tuples of
(original_value, current_value) for all fields that have changed.
- Return type:
Examples
>>> doc = client.documents.get(123) >>> doc.title = "New Title" >>> doc.dirty_fields() {'title': ('Original Title', 'New Title')}
- is_dirty(comparison='both')[source]
Check if any field has changed since last update from the Paperless NGX database.
Determine if the model has unsaved changes by comparing current data with the last saved or retrieved data. New models are always considered dirty.
- Parameters:
comparison (
Literal
['saved'
,'db'
,'both'
]) – Specify the data to compare against: - “saved”: Compare against the last data sent to Paperless NGX - “db”: Compare against the last data retrieved from Paperless NGX - “both”: Compare against both saved and db data (default)- Returns:
True if any field has changed, False otherwise.
- Return type:
Examples
>>> doc = client.documents.get(123) >>> doc.is_dirty() False >>> doc.title = "New Title" >>> doc.is_dirty() True
- classmethod create(**kwargs)[source]
Create a new model instance and save it to the server.
Create a new instance of the model with the specified field values and immediately save it to the Paperless NGX server. This is a convenience method that delegates to the resource’s create method.
- Parameters:
**kwargs (
Any
) – Field values to set on the new model instance.- Returns:
A new model instance that has been saved to the server.
- Return type:
Self
Examples
>>> tag = Tag.create(name="Invoices", color="#ff0000") >>> correspondent = Correspondent.create(name="Electric Company") >>> doc_type = DocumentType.create(name="Bill")
- delete()[source]
Delete this model from the Paperless NGX server.
Remove the model from the server. After calling this method, the model instance should not be used anymore as it no longer represents a valid server object.
- Raises:
ResourceNotFoundError – If the model doesn’t exist on the server.
APIError – If the server returns an error response.
- Return type:
- update_locally(*, from_db=None, skip_changed_fields=False, **kwargs)[source]
Update model attributes without triggering automatic save.
Update the model’s attributes with the provided values without sending changes to the server, regardless of the save_on_write setting. This is useful for local modifications or when applying server updates.
- Parameters:
from_db (
bool
|None
) – Whether the update is from the database. If True, resets the dirty tracking to consider the model clean after the update.skip_changed_fields (
bool
) – Whether to skip updating fields that have unsaved changes. Useful when merging updates from the server with local changes.**kwargs (
Any
) – Field values to update.
- Raises:
ReadOnlyFieldError – If attempting to change a read-only field when from_db is False.
- Return type:
Examples
>>> doc = client.documents.get(123) >>> # Update without saving to server >>> doc.update_locally(title="New Title", correspondent_id=5) >>> # Update from server data >>> doc.update_locally(from_db=True, **server_data)
- update(**kwargs)[source]
Update this model with new values.
Update the model with the provided field values. In BaseModel, this simply calls update_locally without saving. Subclasses (like StandardModel) may implement automatic saving.
Examples
>>> model.update(name="New Name", description="Updated description")
- abstractmethod is_new()[source]
Check if this model represents a new (unsaved) object.
Determine if the model has been saved to the server. Subclasses must implement this method, typically by checking if the model has a valid ID or other server-assigned identifier.
- Returns:
True if the model is new (not yet saved), False otherwise.
- Return type:
Examples
>>> doc = Document.create(title="New Document") >>> doc.is_new() # Returns False after creation >>> >>> # When creating a model instance manually: >>> doc = Document(title="Draft Document") >>> doc.is_new() # Returns True
- should_save_on_write()[source]
Check if the model should save on attribute write.
Determine if changes to model attributes should trigger an automatic save operation based on configuration settings. This method considers both the model’s meta settings and the client settings, with the model’s setting taking precedence.
- Returns:
True if the model should save on write, False otherwise.
- Return type:
- enable_save_on_write()[source]
Enable automatic saving on attribute write.
Set the model’s meta configuration to allow automatic saving whenever an attribute is modified, overriding the client’s default setting. This affects only this specific model instance. :rtype:
None
Examples
>>> doc = client.documents.get(123) >>> doc.enable_save_on_write() >>> doc.title = "New Title" # This will trigger an automatic save
- disable_save_on_write()[source]
Disable automatic saving on attribute write.
Set the model’s meta configuration to prevent automatic saving whenever an attribute is modified, overriding the client’s default setting. This affects only this specific model instance. :rtype:
None
Examples
>>> doc = client.documents.get(123) >>> doc.disable_save_on_write() >>> doc.title = "New Title" # This won't trigger an automatic save >>> doc.save() # Manual save required
- matches_dict(data)[source]
Check if the model matches the provided data.
Compare the model’s current data with a given dictionary to determine if they are equivalent. This is useful for checking if a model needs to be updated based on new data from the server.
- Parameters:
data (
dict
[str
,Any
]) – Dictionary containing the data to compare against.- Returns:
True if the model matches the data, False otherwise.
- Return type:
Examples
>>> doc = client.documents.get(123) >>> new_data = {"id": 123, "title": "Invoice", "correspondent_id": 5} >>> doc.matches_dict(new_data) False # If any values differ
- class paperap.models.abstract.model.StandardModel(**data)[source]
-
Standard model for Paperless-ngx API objects with an ID field.
Extend BaseModel to include a unique identifier and additional functionality for API objects that require an ID. Most Paperless-ngx resources are represented by StandardModel subclasses.
This class adds functionality for: - Tracking whether an object is new or existing - Automatic saving of changes to the server - Refreshing data from the server - Synchronous and asynchronous save operations
- id
Unique identifier for the model from Paperless-ngx.
- _resource
Associated resource for API interactions.
Examples
StandardModel subclasses are typically accessed through the client:
>>> doc = client.documents.get(123) >>> tag = client.tags.create(name="Important") >>> correspondent = client.correspondents.all()[0]
- Parameters:
data (
Any
)
- id: int
- class Meta(model)[source]
Bases:
Meta
Metadata for the StandardModel.
Define metadata specific to StandardModel, including read-only fields and filtering parameters common to all standard Paperless-ngx resources.
- read_only_fields
Fields that should not be modified, including the ‘id’ field which is set by the server.
- supported_filtering_params
Common filtering parameters supported for all standard models, including id-based lookups.
- Parameters:
model (type[_Self])
- read_only_fields: ClassVar[set[str]] = {'id'}
- supported_filtering_params: ClassVar[set[str]] = {'id', 'id__in', 'limit'}
- blacklist_filtering_params: ClassVar[set[str]] = {}
- field_map: dict[str, str] = {}
- filtering_disabled: ClassVar[set[str]] = {}
- filtering_fields: ClassVar[set[str]] = {'_resource', 'id'}
- model: type[_Self]
- name: str
- property resource: StandardResource[Self]
Get the resource associated with this model.
Provide access to the StandardResource instance that handles API interactions for this model type, with support for ID-based operations.
- Returns:
The resource instance for this model type.
- Return type:
StandardResource[Self]
- update(**kwargs)[source]
Update this model with new values and save changes.
Update the model with the provided field values and automatically save the changes to the server if the model is not new. This method combines update_locally and save for convenience.
Note
New (unsaved) instances will be updated locally but not saved automatically. Use create() to save new instances.
Examples
>>> doc = client.documents.get(123) >>> doc.update(title="New Title", correspondent_id=5) >>> # Changes are immediately saved to the server
- refresh()[source]
Refresh the model with the latest data from the server.
Retrieve the latest data for the model from the server and update the model instance with any changes. This is useful when you suspect the server data may have changed due to actions by other users or automated processes.
- Returns:
- True if the model data changed, False if the data is identical
or the refresh failed.
- Return type:
- Raises:
ResourceNotFoundError – If the model is not found on the server (e.g., it was deleted remotely).
Examples
>>> doc = client.documents.get(123) >>> # After some time or operations by other users >>> doc.refresh() # Update with latest data from server
- save(*, force=False)[source]
Save this model to the Paperless NGX server.
Send the current model state to the server, creating a new object or updating an existing one. This is a convenience method that calls save_sync.
- Parameters:
force (
bool
) – Whether to force the save operation even if the model is not dirty or is already saving.- Returns:
True if the save was successful, False otherwise.
- Return type:
Examples
>>> doc = client.documents.get(123) >>> doc.title = "New Title" >>> doc.save() >>> >>> # Force save even if no changes >>> doc.save(force=True)
- save_sync(*, force=False)[source]
Save this model instance synchronously.
Send changes to the server immediately and update the model when the server responds. This method blocks until the save operation is complete.
- Parameters:
force (
bool
) – Whether to force the save operation even if the model is not dirty or is already saving.- Returns:
True if the save was successful, False otherwise.
- Return type:
- Raises:
ResourceNotFoundError – If the resource doesn’t exist on the server.
RequestError – If there’s a communication error with the server.
APIError – If the server returns an error response.
PermissionError – If the user doesn’t have permission to update the resource.
Examples
>>> doc = client.documents.get(123) >>> doc.title = "New Title" >>> success = doc.save_sync() >>> print(f"Save {'succeeded' if success else 'failed'}")
- save_async(*, force=False)[source]
Save this model instance asynchronously.
Send changes to the server in a background thread, allowing other operations to continue while waiting for the server response. The model will be updated with the server’s response when the save completes.
- Parameters:
force (
bool
) – Whether to force the save operation even if the model is not dirty or is already saving.- Returns:
- True if the save was successfully submitted to the background
thread, False otherwise (e.g., if there are no changes to save).
- Return type:
Examples
>>> doc = client.documents.get(123) >>> doc.title = "New Title" >>> # Continue execution immediately while save happens in background >>> doc.save_async() >>> # Do other work...
- is_new()[source]
Check if this model represents a new (unsaved) object.
Determine if the model has been saved to the server by checking if it has a valid ID (non-zero). StandardModel implements this method by checking the id attribute.
- Returns:
True if the model is new (not yet saved), False otherwise.
- Return type:
Examples
>>> doc = Document(title="Draft") # No ID yet >>> doc.is_new() True >>> saved_doc = client.documents.get(123) >>> saved_doc.is_new() False
- __setattr__(name, value)[source]
Override attribute setting to automatically trigger save.
Intercept attribute assignments and trigger an automatic save operation if appropriate based on the save_on_write setting. This enables the “save on write” functionality that makes the model automatically sync changes to the server.
Notes
Private attributes (starting with ‘_’) never trigger autosave
Autosave only happens when model status is READY
Autosave is skipped for new models or when save_on_write is False
- __str__()[source]
Human-readable string representation.
This method returns a string representation of the model, typically used for logging and debugging purposes.
- Returns:
A string representation of the model.
- Return type:
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'populate_by_name': True, 'use_enum_values': True, 'validate_assignment': True, 'validate_default': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].