pynamodb / PynamoDB

A pythonic interface to Amazon's DynamoDB
http://pynamodb.readthedocs.io
MIT License
2.45k stars 427 forks source link

Supporting Model Inheritance in Pynamo #439

Open betamoo opened 6 years ago

betamoo commented 6 years ago

Last Modified: 01/25/2018

Summary

PynamoDB currently doesn’t -guarantee to- support inheritance. We aim at supporting two different types of inheritance in Pynamo: Abstract & Proxy inheritance (explained later) in order to allow more flexible ways of designing/describing models for Pynamo users.

Goal

Support two types of inheritance Abstract & Proxy inheritance.

Non-goal: supporting Multi table inheritance.

Context

PynamoDB allows describing, creating and accessing tables in DynamoDB through pythonic styled methods. Creating tables in Pynamo is -mostly- declarative: in that by declaring python classes, the user can create & get access to DynamoDB tables and data.

Model inheritance is a feature that is supported by some ORMs, such as: Django

The three types of inheritance supported in Django:

1. Abstract Inheritance In which, the parent (inherited model) is an abstract model that doesn’t correspond to a table, but rather just a definition or an information holder for the children (inheriting models) to follow.

A use case of abstract inheritance is when more than one model share common field descriptions, the user can have an abstract class with the common fields and inherit it by different children, that way the user saves work that that otherwise would be redundant.

2. Proxy Inheritance In this case, the inheriting child (or children) provides) only an alternate way to access the same table of the parent model. Both the proxies and their parent correspond to the same table but can have different configurations or different behaviours.

A use case for proxy inheritance is when a user needs to access the same table with two or more different configurations (different port or different RCU/WCU). Another use case is to mask certain fields in the child proxy such that it only has access to a subset of it’s parent fields.

3. Multi table inheritance In which both the parent and each of the children represent different tables, but with links between the common fields and attributes. That means that some fields of corresponding models are mirrored in the different tables and have to stay in sync (including for example cascade delete).

A use case for multi table inheritance, is when the user needs to create a table that shadows the original table. The inheritance relation should take care of the data replication.

Plan

As mentioned earlier, we are aiming only to support abstract inheritance and proxy inheritance.

We are going to skip the multi table inheritance (at least for now) as it is almost impossible/will introduce many complications in a non relational key-value database like DynamoDB.

We are planning to approach the inheritance behaviour as follows:

Abstract Inheritance Behaviour

Proxy Inheritance Behaviour

General Notes & Behaviour

Questions yet to be answered:

Sample Code

Abstract Inheritance Example:

class UserModelBase1(Model):

    class Meta:
        abstract = True

    user_name = UnicodeAttribute(hash_key=True)
    email = UnicodeAttribute()

class UserModelBase2(UserModelBase1):
    custom_aliases = UnicodeSetAttribute(attr_name=**'aliases'**)
    views = NumberAttribute(null=True)

class UserModelBase3(UserModelBase2):
    icons = BinarySetAttribute()

class UserModel(UserModelBase3):

    class Meta:
        table_name = 'UserModel'
        abstract = False

    numbers = NumberSetAttribute()
    is_active = BooleanAttribute(null=True)
    signature = UnicodeAttribute(null=True)

UserModel.create_table(read_capacity_units=2, write_capacity_units=2)

Proxy Inheritance Example:


class UserModel(Model):

     class Meta:
         table_name = 'UserModel'
         abstract = False

    user_name = UnicodeAttribute(hash_key=True)
    email = UnicodeAttribute()
    icons = BinarySetAttribute()
    numbers = NumberSetAttribute()
    is_active = BooleanAttribute(null=True)
    signature = UnicodeAttribute(null=True)

class UserModelProxy1(UserModel):

     class Meta:
         proxy = True

class UserModelProxy2(UserModel):

     class Meta:
         read_capacity_units = 2
         write_capacity_units = 2
         proxy = True

Testing strategy

Abstract Testing

Proxy Testing

Abstract/Proxy Testing

Related Tickets

Proposed PR

PR for abstract inheritance changes: https://github.com/pynamodb/PynamoDB/pull/440

the PR for proxy inheritance is coming soon

Jamim commented 6 years ago

Hi everyone, Are there any updates?

Jamim commented 6 years ago

Oh, I see there is a related PR #440 :+1: