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
class TyreAdmin(sqla.ModelView):
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
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`
the ``form_excluded_pk_columns_from_unique_validation`` attribute can, and must, be used, to exclude *all*
primary-key-columns from this check. Your database will tell you via ``Sqlalchemy``, if the operation
was successfull or not. (Watch out for IntegrityErrors).
When having multiple primary keys, **no** validation for uniqueness *prior* to saving of the object will be done. Saving
a model that violates a unique-constraint leads to an Sqlalchemy-Integrity-Error. In this case, ``Flask-Admin`` displays
a proper error message and you can change the data in the form. When the application has been started with ``debug=True``
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.
......
......@@ -39,12 +39,11 @@ class Tyre(db.Model):
class CarAdmin(sqla.ModelView):
column_display_pk = True
form_columns = ['id', 'desc']
class TyreAdmin(sqla.ModelView):
column_display_pk = True
form_columns = ['car', 'tyre_id', 'desc']
form_excluded_pk_columns_from_unique_validation = ('car_id', 'tyre_id')
if __name__ == '__main__':
# Create admin
......
......@@ -12,7 +12,7 @@ from flask.ext.admin._compat import iteritems
from .validators import Unique
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:
# Field has better input parsing capabilities.
......@@ -166,8 +166,8 @@ class AdminModelConverter(ModelConverterBase):
if prop.key not in form_columns:
return None
# PK can be explicitely excluded from uniquenes-validation
if prop.key not in self.view.form_excluded_pk_columns_from_unique_validation:
# Current Unique Validator does not work with multicolumns-pks
if not has_multiple_pks(model):
kwargs['validators'].append(Unique(self.session,
model,
column))
......
......@@ -67,3 +67,11 @@ def get_column_for_current_model(prop):
else:
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):
if self.form_choices is None:
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)
# Primary key
......
......@@ -312,22 +312,6 @@ class BaseModelView(BaseView, ActionsMixin):
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
"""
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