How organize double-inheritance in web2py

107 views
Skip to first unread message

Georgy Silkly

unread,
Jan 27, 2016, 6:05:57 PM1/27/16
to web2py-users
I have 4 classes: Abonent, Person, Company and Provider.
Person and Company are (sublasses of) Abonents, and Provider is (subclasses of) Company.
In django I can write
class Abonent(models.Model): pass
class Person(Abonent): pass
class Company(Abonent): pass
class Provider(Company): pass
how it will be in web2py?
follow does not works:
db.define_table('abonent')
db.define_table('person', Field('abonent', db.abonent), primarykey=['abonent'])
db.define_table('company', Field('abonent', db.abonent), primarykey=['abonent'])
db.define_table('provider', Field('company', db.company), primarykey=['company'])
and this
db.define_table('abonent')
db.define_table('person', Field('abonent', db.abonent), primarykey=['abonent'])
db.define_table('company', Field('abonent', db.abonent), primarykey=['abonent'])
db.define_table('provider', Field('company', db.company.abonent), primarykey=['company'])
and this
db.define_table('abonent')
db.define_table('person', Field('abonent', type='reference abonent'), primarykey=['abonent'])
db.define_table('company', Field('abonent', type='reference abonent'), primarykey=['abonent'])
db.define_table('provider', Field('company', type='reference company.abonent'), primarykey=['company'])

Massimo Di Pierro

unread,
Jan 27, 2016, 6:24:24 PM1/27/16
to web2py-users
db.define_table('abonent', Field('a'))
db.define_table('person', db.abonet, Field('b')) # has a,b
db.define_table('company', db.abonet, Field('c')) # has a,c
db.define_table('provider', db.company, Field('d')) # has a,c,d

RekGRpth

unread,
Jan 28, 2016, 2:58:02 AM1/28/16
to web2py-users
Thank You! And I found how to do that I want. I added support of 'native postgres inheritance' into web2py:

~/web2py/gluon/packages/dal/pydal/git diff
diff --git a/pydal/adapters/base.py b/pydal/adapters/base.py
index 94c6819..9ddfaad 100644
--- a/pydal/adapters/base.py
+++ b/pydal/adapters/base.py
@@ -417,11 +417,17 @@ class BaseAdapter(with_metaclass(AdapterMeta, ConnectionPool)):
             sql_fields_aux[field_name] = dict(sql=ftype)
             # Postgres - PostGIS:
             # geometry fields are added after the table has been created, not now
+            if field_name in table.inherit_fields:
+                continue
             if not (self.dbengine == 'postgres' and \
                         field_type.startswith('geom')):
                 fields.append('%s %s' % (field.sqlsafe_name, ftype))
         other = ';'
 
+        if table.inherit_tables:
+            other = 'INHERITS (%s);' % ','.join(self.QUOTE_TEMPLATE % inherit_table for inherit_table in table.inherit_tables)
+            fields.append('PRIMARY KEY (%s)' % (self.QUOTE_TEMPLATE % table._id.name))
+
         # backend-specific extensions to fields
         if self.dbengine == 'mysql':
             if not hasattr(table, "_primarykey"):
diff --git a/pydal/objects.py b/pydal/objects.py
index e63eaab..f0adb29 100644
--- a/pydal/objects.py
+++ b/pydal/objects.py
@@ -278,6 +278,8 @@ class Table(Serializable, BasicStorage):
             fieldnames.add(field.name)
             if field.type == 'id':
                 self._id = field
+        self.inherit_tables = []
+        self.inherit_fields = []
         for field in fields:
             if isinstance(field, (FieldVirtual, FieldMethod)):
                 virtual_fields.append(field)
@@ -287,10 +289,13 @@ class Table(Serializable, BasicStorage):
                 include_new(field)
             elif isinstance(field, Table):
                 table = field
+                self.inherit_tables.append(table._tablename)
+                self.inherit_fields.append('id')
                 for field in table:
                     if field.name not in fieldnames and field.type != 'id':
                         t2 = not table._actual and self._tablename
                         include_new(field.clone(point_self_references_to=t2))
+                        self.inherit_fields.append(field.name)
             elif isinstance(field, dict) and field['fieldname'] not in fieldnames:
                 include_new(Field(**field))
             elif not isinstance(field, (Field, Table)):


четверг, 28 января 2016 г., 4:24:24 UTC+5 пользователь Massimo Di Pierro написал:

Filipe Reis

unread,
Jul 8, 2017, 4:54:51 PM7/8/17
to web2py-users
I was trying to implement this but I can't understand one thing.

In this example:
db.define_table('abonent', Field('a'))
db.define_table('person', db.abonet, Field('b')) # has a,b
db.define_table('company', db.abonet, Field('c')) # has a,c

You would create many persons and companies, how would you select them all from the abonent? Since I tried it and the abonent table will be empty...

For example:

some table 1------n abonent , and that abonent is either a person or a company.

Any ideas?


Anthony

unread,
Jul 9, 2017, 3:10:47 PM7/9/17
to web2py-users

The above code simply creates db.person and db.company tables that have the same fields as the db.abonent table. However, records in the three tables are separate -- a record in the db.person table does not also appear in the db.abonet table. If you want a single collection of records that can have different types, you should probably just have a single table with some kind of "type" field.

Anthony

Anthony

unread,
Jul 9, 2017, 3:22:26 PM7/9/17
to web2py-users

And note, the above is akin to Django's abstract base class approach to model inheritance.

Perhaps you are more interested in the multi-table inheritance approach. With this approach, Django uses class inheritance to automatically generate one-to-one relations between tables. With the web2py DAL, you would simply do this explicitly by creating a reference field from the child table to the parent.

Anthony
Reply all
Reply to author
Forward
0 new messages