Discriminate Pony-generated fields in entities (implicit primary key) #77

Closed
crazygolem opened this Issue Sep 25, 2014 · 1 comment

Projects

None yet

2 participants

@crazygolem

When Pony generates for an Entity a field that has not been specified by the user in the class definition (I know of this behavior only for Entity subclasses that do not specify a PrimaryKey field), there is currently no straightforward way to now whether that field was specified by the user or generated by Pony.

Would it be possible to have an is_implicit (or any better name) field in Attribute that is False except when the field was generated by Pony, like in the case of an implicit primary key?

@kozlovsky
Contributor

Thanks for the suggestion, added to PonyORM 0.6

I know of this behavior only for Entity subclasses that do not specify a PrimaryKey field

The value of is_implicit field of primary key attribute has no relation to subclasses. Even for single class its primary key can be implicit:

>>> from pony.orm import *
>>> db = Database('sqlite', ':memory:')
>>> class Person(db.Entity):
...     name = Required(str)
...     
>>> Person._attrs_
[Person.id, Person.name]
>>> Person.id.is_implicit
True
>>> Person.name.is_implicit
False

In case of inheritance, it is discriminator attribute which can be implicit. Pony uses the value of discriminator attribute in order to determine a Python class which correspond to the specific database row:

>>> db = Database('sqlite', ':memory:')
>>> class Person(db.Entity):
...     name = Required(str)
... 
>>> class Student(Person):
...     gpa = Required(float)
...     
>>> Person._attrs_
[Person.id, Person.name, Person.classtype]
>>> Student._attrs_
[Person.id, Person.name, Person.classtype, Student.gpa]
>>> Person._discriminator_attr_
Person.classtype
>>> Person._discriminator_
'Person'
>>> Student._discriminator_
'Student'
>>> Person._discriminator_attr_.is_implicit
True
>>> Person._discriminator_attr_.py_type
<type 'str'>
>>> db.generate_mapping(create_tables=True)
>>> p1 = Person(name='John')
>>> s1 = Student(name='Mike', gpa=4.5)
>>> p1.classtype
'Person'
>>> s1.classtype
'Student'

It is possible to specify custom discriminator attribute which type is not str:

>>> class Person(db.Entity):
...     _discriminator_ = 1
...     kind = Discriminator(int)
...     name = Required(str)
... 
>>> class Student(Person):
...     _discriminator_ = 2
...     gpa = Required(float)
... 
>>> db.generate_mapping(create_tables=True)
>>> p1 = Person(name='John')
>>> s1 = Student(name='Mike', gpa=4.5)
>>> Person._discriminator_attr_
Person.kind
>>> Person._discriminator_attr_.is_implicit
False
>>> p1.kind
1
>>> p1._discriminator_attr_
1
>>> s1._discriminator_attr_
2

You may wonder why the value of p1._discriminator_attr_ is 1 here and not Person.kind. This is because in Pony each attribute is a descriptor, and when descriptor accessed from the object instance, the value of descriptor.__get__(obj) is returned and not the descriptor itself. In order to retrieve discriminator attribute of specific entity instance in a generic way, you can write obj.__class__._discriminator_attr_.

@kozlovsky kozlovsky closed this in 2320660 Oct 30, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment