Commit 6ddbfc79 authored by Serge S. Koval's avatar Serge S. Koval

Merge pull request #280 from sumpfgottheit/sqla_inheritance_primary_key

process inherited primary keys correctly
parents 7a35ce85 1e8520da
...@@ -12,6 +12,7 @@ from flask.ext.admin._compat import iteritems ...@@ -12,6 +12,7 @@ from flask.ext.admin._compat import iteritems
from .validators import Unique from .validators import Unique
from .fields import QuerySelectField, QuerySelectMultipleField, InlineModelFormList from .fields import QuerySelectField, QuerySelectMultipleField, InlineModelFormList
from .tools import is_inherited_primary_key, get_column_for_current_model
try: try:
# Field has better input parsing capabilities. # Field has better input parsing capabilities.
...@@ -132,10 +133,13 @@ class AdminModelConverter(ModelConverterBase): ...@@ -132,10 +133,13 @@ class AdminModelConverter(ModelConverterBase):
if hasattr(prop, 'columns'): if hasattr(prop, 'columns'):
# Check if more than one column mapped to the property # Check if more than one column mapped to the property
if len(prop.columns) != 1: if len(prop.columns) != 1:
raise TypeError('Can not convert multiple-column properties (%s.%s)' % (model, prop.key)) if is_inherited_primary_key(prop):
column = get_column_for_current_model(prop)
# Grab column else:
column = prop.columns[0] raise TypeError('Can not convert multiple-column properties (%s.%s)' % (model, prop.key))
else:
# Grab column
column = prop.columns[0]
# Do not display foreign keys - use relations # Do not display foreign keys - use relations
if column.foreign_keys: if column.foreign_keys:
......
...@@ -25,3 +25,39 @@ def get_primary_key(model): ...@@ -25,3 +25,39 @@ def get_primary_key(model):
return p.key return p.key
return None return None
def is_inherited_primary_key(prop):
"""
Return True, if the ColumnProperty is an inherited primary key
Check if all columns are primary keys and _one_ does not have a foreign key -> looks like joined
table inheritance: http://docs.sqlalchemy.org/en/latest/orm/inheritance.html with "standard
practice" of same column name.
:param prop: The ColumnProperty to check
:return: Boolean
:raises: Exceptions as they occur - no ExceptionHandling here
"""
return len([column for column in prop.columns if column.primary_key]) == len(prop.columns) and \
len([column for column in prop.columns if column.foreign_keys]) == len(prop.columns)-1
def get_column_for_current_model(prop):
"""
Return the Column() of the ColumnProperty "prop", that refers to the current model
When using inheritance, a ColumnProperty may contain multiple columns. This function
returns the Column(), the belongs to the Model of the ColumnProperty - the "current"
model
:param prop: The ColumnProperty
:return: The column for the current model
:raises: TypeError if not exactely one Column() for the current model could be found.
All other Exceptions not handled here but raised
"""
candidates = [column for column in prop.columns if column.expression == prop.expression]
if len(candidates) != 1:
raise TypeError('Not exactly one column for the current model found. ' +
'Found %d columns for property %s' % (len(candidates), prop))
else:
return candidates[0]
...@@ -15,7 +15,7 @@ from flask.ext.admin._backwards import ObsoleteAttr ...@@ -15,7 +15,7 @@ from flask.ext.admin._backwards import ObsoleteAttr
from flask.ext.admin.contrib.sqla import form, filters, tools from flask.ext.admin.contrib.sqla import form, filters, tools
from .typefmt import DEFAULT_FORMATTERS from .typefmt import DEFAULT_FORMATTERS
from .tools import is_inherited_primary_key, get_column_for_current_model
class ModelView(BaseModelView): class ModelView(BaseModelView):
""" """
...@@ -308,10 +308,18 @@ class ModelView(BaseModelView): ...@@ -308,10 +308,18 @@ class ModelView(BaseModelView):
if self.column_display_all_relations or p.direction.name == 'MANYTOONE': if self.column_display_all_relations or p.direction.name == 'MANYTOONE':
columns.append(p.key) columns.append(p.key)
elif hasattr(p, 'columns'): elif hasattr(p, 'columns'):
# TODO: Check for multiple columns column_inherited_primary_key = False
column = p.columns[0] if len(p.columns) != 1:
if is_inherited_primary_key(p):
column = get_column_for_current_model(p)
else:
raise TypeError('Can not convert multiple-column properties (%s.%s)' % (model, p.key))
else:
# Grab column
column = p.columns[0]
if column.foreign_keys: # An inherited primary key has a foreign key as well
if column.foreign_keys and not is_inherited_primary_key(p):
continue continue
if not self.column_display_pk and column.primary_key: if not self.column_display_pk and column.primary_key:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment