New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

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

Comments

Projects
None yet
2 participants
@crazygolem

crazygolem commented Sep 25, 2014

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

This comment has been minimized.

Show comment
Hide comment
@kozlovsky

kozlovsky Oct 30, 2014

Member

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_.

Member

kozlovsky commented Oct 30, 2014

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