How to map common polymorphic parameters on parent model when using a generic association with discriminator

Viewed 27

The following example, declares a Mixin which provides an init extensions to automatically create a "report" on a submit table.

In this example, it also extends the model with upload_datetime for the aim of simplicity, however, the assciation_proxy might point to any other property interesting for the submit.

class Submit(db.Model):
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    resource_type = Column(String, nullable=False)
    resource_id = association_proxy("resource", "id")
    upload_datetime = association_proxy("resource", "upload_datetime")
    ...

    __mapper_args__ = {
        'polymorphic_on': resource_type,
    }


class CreatesSubmit():
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__class__._submit_report_class(resource=self)

    @declared_attr
    def upload_datetime(cls):
        return Column(DateTime, nullable=False, default=dt.now)

    @declared_attr
    def _submit_report_id(cls):
        return Column(ForeignKey('submit.id'))

    @declared_attr
    def _submit_report_class(cls):
        return type(
            f"{cls.__name__}SubmitReport", (Submit,),
            dict(
                __mapper_args__={
                    'polymorphic_identity': cls.__name__.lower(),
                },
            ),
        )

    @declared_attr
    def submit_report(cls):
        return relationship(
            cls._submit_report_class, cascade="all",
            backref=backref("resource", uselist=False),
        )

    def special_methods(self):
        ...

All classes that inherit this Mixin should create a "submit" which references the parent as "resource". For example:

class Benchmark(CreatesSubmit, db.Model):
    ...

benchmark = Benchmark()

Allows:

submit = benchmark.submit_report
assert submit.resource == benchmark

However, I want to be able to filter submits usign the upload_datetime attibute, for example:

query1 = Benchmark.query.filter(Benchmark.upload_datetime < date)
query2 = Submit.query.filter(Submit.upload_datetime < date)

However, on query2 I get InvalidRequestError: Mapper 'mapped class Submit->submit' has no property 'resource'.

Notes:

  • upload_datetime is an association_proxy which relies on "resource", only available at the 'dynamic created' polymorphic table.
  • Why not to have "upload_datetime" on Submit? A submit will be deleted at some point, but upload_datetime should be persistent.
  • I read about 'with_polymorphic': '*' but I did not manage to make it work.
  • See discriminator_on_association for the generic association I am basing this example.
0 Answers
Related