Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7779565
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 1, 20262026-06-01T18:40:15+00:00 2026-06-01T18:40:15+00:00

So say I have some classes X, Y and Z using SQLAlchemy declarative syntax

  • 0

So say I have some classes X, Y and Z using SQLAlchemy declarative syntax to define some simple columns and relationships

Requirements:

  1. At the class level, (X|Y|Z).primary_keys returns a collection of
    the respective class’ primary keys’ (InstrumentedAttribute
    objects) I also want (X|Y|Z).relations to reference the class’
    relations in the same way

  2. At the instance level, I would like the same attributes to reference
    those attributes’ instantiated values, whether they’ve been
    populated using my own constructors, individual attributes
    setters, or whatever SQLAlchemy does when it retrieves rows from
    the db.

So far I have the following.

import collections 
import sqlalchemy
import sqlalchemy.ext.declarative
from sqlalchemy import MetaData, Column, Table, ForeignKey, Integer, String, Date, Text
from sqlalchemy.orm import relationship, backref

class IndexedMeta(sqlalchemy.ext.declarative.DeclarativeMeta):
        """Metaclass to initialize some class-level collections on models"""
    def __new__(cls, name, bases, defaultdict):
        cls.pk_columns = set()
        cls.relations = collections.namedtuple('RelationshipItem', 'one many')( set(), set())
        return super().__new__(cls, name, bases, defaultdict)

Base = sqlalchemy.ext.declarative.declarative_base(metaclass=IndexedMeta)


def build_class_lens(cls, key, inst):
    """Populates the 'indexes' of primary key and relationship attributes with the attributes' names. Additionally, separates "x to many" relationships from "x to one" relationships and associates "x to one" relathionships with the local-side foreign key column"""
    if isinstance(inst.property, sqlalchemy.orm.properties.ColumnProperty):
        if inst.property.columns[0].primary_key:
            cls.pk_columns.add(inst.key)

    elif isinstance(inst.property, sqlalchemy.orm.properties.RelationshipProperty):
        if inst.property.direction.name == ('MANYTOONE' or 'ONETOONE'):
            local_column = cls.__mapper__.get_property_by_column(inst.property.local_side[0]).key
            cls.relations.one.add( (local_column, inst.key) )
        else:
            cls.relations.many.add(inst.key)


sqlalchemy.event.listen(Base, 'attribute_instrument', build_class_lens)

class Meeting(Base):
    __tablename__ = 'meetings'
    def __init__(self, memo):
        self.memo = memo
    id = Column(Integer, primary_key=True)
    date = Column(Date)
    memo = Column('note', String(60), nullable=True)
    category_name = Column('category', String(60), ForeignKey('categories.name'))
    category = relationship("Category", backref=backref('meetings'))
    topics = relationship("Topic",
        secondary=meetings_topics,
        backref="meetings")

...
...

Ok, so that gets me by on the class level, though I feel like I am doing silly things with metaclasses, and I get some strange intermittent errors where the ‘sqlalchemy’ module allegedly isn’t recognized in build_class_lens and evals to Nonetype.

I am not quite sure how I should proceed at the instance level.
I’ve looked into the events interface. I see the ORM event init, but it seems to run prior to the __init__ function defined on my models, meaning the instance attributes haven’t yet been populated at that time, so I can’t build my ‘lens’ on them.
I also wonder if the Attribute event set might be of help. That is my next try, though i still wonder if it is the most appropriate way.

All in all I really wonder if I am missing some really elegant way to approach this problem.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-01T18:40:17+00:00Added an answer on June 1, 2026 at 6:40 pm

    I think the metaclass thing with declarative goes by the old XML saying, “if you have a problem, and use XML, now you have two problems”. The metaclass in Python is useful pretty much as a hook to detect the construction of new classes, and that’s about it. We now have enough events that there shouldn’t be any need to use a metaclass beyond what declarative already does.

    In this case I’d go a little further and say that the approach of trying to actively build up these collections is not really worth it – it’s much easier to generate them lazily, as below:

    from sqlalchemy import *
    from sqlalchemy.orm import *
    from sqlalchemy.ext.declarative import declarative_base
    import collections
    from sqlalchemy.orm.properties import RelationshipProperty
    
    class memoized_classproperty(object):
        """A decorator that evaluates once at the class level, 
           assigns the new value to the class.
        """
    
        def __init__(self, fget, doc=None):
            self.fget = fget
            self.__doc__ = doc or fget.__doc__
            self.__name__ = fget.__name__
    
        def __get__(desc, self, cls):
            result = desc.fget(cls)
            setattr(cls, desc.__name__, result)
            return result
    
    class Lens(object):
        @memoized_classproperty
        def pk_columns(cls):
            return class_mapper(cls).primary_key
    
        @memoized_classproperty
        def relations(cls):
            props = collections.namedtuple('RelationshipItem', 'one many')(set(), set())
            # 0.8 will have "inspect(cls).relationships" here
            mapper = class_mapper(cls)
            for item in mapper.iterate_properties:
                if isinstance(item, RelationshipProperty):
                    if item.direction.name == ('MANYTOONE' or 'ONETOONE'):
                        local_column = mapper.get_property_by_column(item.local_side[0]).key
                        props.one.add((local_column, item.key))
                    else:
                        props.many.add(item.key)
            return props
    
    Base= declarative_base(cls=Lens)
    
    meetings_topics = Table("meetings_topics", Base.metadata,
        Column('topic_id', Integer, ForeignKey('topic.id')),
        Column('meetings_id', Integer, ForeignKey('meetings.id')),
    )
    class Meeting(Base):
        __tablename__ = 'meetings'
        def __init__(self, memo):
            self.memo = memo
        id = Column(Integer, primary_key=True)
        date = Column(Date)
        memo = Column('note', String(60), nullable=True)
        category_name = Column('category', String(60), ForeignKey('categories.name'))
        category = relationship("Category", backref=backref('meetings'))
        topics = relationship("Topic",
            secondary=meetings_topics,
            backref="meetings")
    
    class Category(Base):
        __tablename__ = 'categories'
        name = Column(String(50), primary_key=True)
    
    class Topic(Base):
        __tablename__ = 'topic'
        id = Column(Integer, primary_key=True)
    
    print Meeting.pk_columns
    print Meeting.relations.one
    
    # assignment is OK, since prop is memoized
    Meeting.relations.one.add("FOO")
    
    print Meeting.relations.one
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Let's say I have some classes like this: abstract class View(val writer: XMLStreamWriter) {
I have some questions about the affects of using concrete classes and interfaces. Say
Say I have some code like namespace Portal { public class Author { public
Lets say we have some basic AR model. class User < ActiveRecord::Base attr_accessible :firstname,
Say I have an interface and some classes: public interface IPanel<ComponentType extends Component> {
I have a (simple) question about generic classes in c++. I have some knowledge
I'm using LinqToSql classes in an ASP.NET website and let's say I have an
Say you have these two classes. public class Author { public int ID {get;
Say I have two classes One, the Foo class, interfaces with the user, and
Say I have some windows method and a struct: struct SomeStruct{ int foo; int

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.