Annotated resources¶
As of Odin 2.0, resources can now be defined using Python type annotations. This greatly simplifies definition of resource structures while maintaining compatibility with all existing features. Types defined using the existing odin.Resource base class can be used in conjunction with new annotation style resources.
Defining annotated resources¶
The annotated resource syntax offers many rich ways of representing your resources. Here’s a quick example:
import odin
class Author(odin.AnnotatedResource):
name: str
class Book(odin.AnnotatedResource):
title: str
author: Author
genre: Optional[str] = odin.Options(max_length=255)
num_pages: int = odin.Options(min_value=1)
Tip
If you prefer the shorthand odin.AResource can be used in place of odin.AnnotatedResource
From this we can see that a resource is a collection of fields, each field maps to a specific data type and accepts options that describe validation rules and how data is handled.
The above example also demonstrates relationships between the two resources. This simple example allows for another object to be attached to a book. With these simple primitives complex data-structures can be built.
Working with resources¶
Just like any other resource the API behaves the same:
# Import the resources we created from our "library" app
>>> from library.resources import Author, Book
# Create an instance of an Author
>>> a = Author(name="Iain M. Banks")
# Create an instance of a Book
>>> b = Book(title="Consider Phlebas", author=a, genre="Space Opera", num_pages=471)
>>> b
<Book: library.resources.Book resource>
# Fields are represented as attributes on the Python object.
>>> b.title
'Consider Phlebas'
# DictAs fields are references to other resources.
>>> b.author.name
'Iain M. Banks'
# Get all the data as a dict
>>> a.to_dict()
{'name': 'Iain M. Banks'}
# Validate that the information entered is valid.
# Create an instance of a Book
>>> b = Book(title="Consider Phlebas", genre="Space Opera", num_pages=471)
>>> b.full_clean()
ValidationError: {'author': [{'name': ['This field cannot be null.']}]}
Abstract Resources¶
Abstract resources no longer require the use of a Meta
block then are identified through the use of a keyword
argument eg:
import odin
class LibraryBase(odin.AnnotatedResource, abstract=True):
"""
Common base class for library resources
"""
name: str
class Library(LibraryBase):
address: str
The Library
resource inherits the _name_ field from LibraryBase
but cannot be instantiated directly itself.