Commit 22c925e2 authored by Florian Sachs's avatar Florian Sachs

handle multiple pks in AdminModelConverter.converter()

* New helper-function `contrib.sqla.tools.has_multiple_pks(model)`
* The unique validator is only added to the primary key column in `converter()`, when the model does not have multiple primary keys.
* Removed option `form_excluded_pk_columns_from_unique_validation`
* documentation updated
* example updated
parent 0ee9e4cb
...@@ -133,16 +133,15 @@ To be able to CRUD the ``Tyre`` class, two steps are necessary, when definig the ...@@ -133,16 +133,15 @@ To be able to CRUD the ``Tyre`` class, two steps are necessary, when definig the
class TyreAdmin(sqla.ModelView): class TyreAdmin(sqla.ModelView):
form_columns = ['car', 'tyre_id', 'desc'] form_columns = ['car', 'tyre_id', 'desc']
form_excluded_pk_columns_from_unique_validation = ('car_id', 'tyre_id')
The ``form_columns`` needs to be explizit, as per default only one primary key is displayed. When, like in this The ``form_columns`` needs to be explizit, as per default only one primary key is displayed. When, like in this
example, one part of the key is a foreign key, do not include the foreign-key-columns here, but the example, one part of the key is a foreign key, do not include the foreign-key-columns here, but the
coresponding relationship. corresponding relationship.
Per default, all pimary-key-columns are validated for uniquenes. As describe in :doc:`api/mod_model` When having multiple primary keys, **no** validation for uniqueness *prior* to saving of the object will be done. Saving
the ``form_excluded_pk_columns_from_unique_validation`` attribute can, and must, be used, to exclude *all* a model that violates a unique-constraint leads to an Sqlalchemy-Integrity-Error. In this case, ``Flask-Admin`` displays
primary-key-columns from this check. Your database will tell you via ``Sqlalchemy``, if the operation a proper error message and you can change the data in the form. When the application has been started with ``debug=True``
was successfull or not. (Watch out for IntegrityErrors). the ``werkzeug`` debugger catches the exception and displays the stacktrace.
A standalone script with the Examples from above can be found in the examples directory. A standalone script with the Examples from above can be found in the examples directory.
......
...@@ -39,12 +39,11 @@ class Tyre(db.Model): ...@@ -39,12 +39,11 @@ class Tyre(db.Model):
class CarAdmin(sqla.ModelView): class CarAdmin(sqla.ModelView):
column_display_pk = True column_display_pk = True
form_columns = ['id', 'desc']
class TyreAdmin(sqla.ModelView): class TyreAdmin(sqla.ModelView):
column_display_pk = True column_display_pk = True
form_columns = ['car', 'tyre_id', 'desc'] form_columns = ['car', 'tyre_id', 'desc']
form_excluded_pk_columns_from_unique_validation = ('car_id', 'tyre_id')
if __name__ == '__main__': if __name__ == '__main__':
# Create admin # Create admin
......
...@@ -12,7 +12,7 @@ from flask.ext.admin._compat import iteritems ...@@ -12,7 +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 from .tools import is_inherited_primary_key, get_column_for_current_model, has_multiple_pks
try: try:
# Field has better input parsing capabilities. # Field has better input parsing capabilities.
...@@ -166,8 +166,8 @@ class AdminModelConverter(ModelConverterBase): ...@@ -166,8 +166,8 @@ class AdminModelConverter(ModelConverterBase):
if prop.key not in form_columns: if prop.key not in form_columns:
return None return None
# PK can be explicitely excluded from uniquenes-validation # Current Unique Validator does not work with multicolumns-pks
if prop.key not in self.view.form_excluded_pk_columns_from_unique_validation: if not has_multiple_pks(model):
kwargs['validators'].append(Unique(self.session, kwargs['validators'].append(Unique(self.session,
model, model,
column)) column))
......
...@@ -67,3 +67,11 @@ def get_column_for_current_model(prop): ...@@ -67,3 +67,11 @@ def get_column_for_current_model(prop):
else: else:
return candidates[0] return candidates[0]
def has_multiple_pks(model):
"""Return True, if the model has more than one primary key
"""
if not hasattr(model, '_sa_class_manager'):
raise TypeError('model must be a sqlalchemy mapped model')
pks = model._sa_class_manager.mapper.primary_key
return len(pks) > 1
...@@ -259,9 +259,6 @@ class ModelView(BaseModelView): ...@@ -259,9 +259,6 @@ class ModelView(BaseModelView):
if self.form_choices is None: if self.form_choices is None:
self.form_choices = {} self.form_choices = {}
if self.form_excluded_pk_columns_from_unique_validation is None:
self.form_excluded_pk_columns_from_unique_validation = ()
super(ModelView, self).__init__(model, name, category, endpoint, url) super(ModelView, self).__init__(model, name, category, endpoint, url)
# Primary key # Primary key
......
...@@ -312,22 +312,6 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -312,22 +312,6 @@ class BaseModelView(BaseView, ActionsMixin):
form_excluded_columns = ('last_name', 'email') form_excluded_columns = ('last_name', 'email')
""" """
form_excluded_pk_columns_from_unique_validation = None
"""
Primary Key Columns, that should explicitely excluded from Validation for uniquenes.
Primary Keys are automatically checked for uniqueness *prior* to the database-save operation.
If your model consists of multiple primary keys, list them here, so the built-in validation
is disabled.
The constraints-check of the database will, of course, still prevent you from saving two identical
primary keys, regardless of how many columns are part of your primary key.
For example::
class MyModelView(BaseModelView):
form_excluded_pk_columns_from_unique_validation = ('id', 'secondid')
"""
form_overrides = None form_overrides = None
""" """
Dictionary of form column overrides. Dictionary of form column overrides.
......
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