Unverified Commit 4e3e7e68 authored by Serge S. Koval's avatar Serge S. Koval Committed by GitHub

Merge pull request #1875 from flask-admin/hybrid-prop-search

Support search on SQLAlchemy hybrid property
parents 920af0ad 62692891
......@@ -4,6 +4,7 @@ from flask import Flask, Markup
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import composite
from sqlalchemy import sql, cast
import uuid
import random
import string
......@@ -85,9 +86,13 @@ class User(db.Model):
def phone_number(self):
if self.dialling_code and self.local_phone_number:
number = str(self.local_phone_number)
return "+{} ({}){} {} {}".format(self.dialling_code, number[0], number[1:3], number[3:6], number[6::])
return "+{} ({}) {} {} {}".format(self.dialling_code, number[0], number[1:3], number[3:6], number[6::])
return
@phone_number.expression
def phone_number(cls):
return sql.operators.ColumnOperators.concat(cast(cls.dialling_code, db.String), cls.local_phone_number)
def __str__(self):
return "{}, {}".format(self.last_name, self.first_name)
......@@ -197,6 +202,7 @@ class UserAdmin(sqla.ModelView):
column_searchable_list = [
'first_name',
'last_name',
'phone_number',
'email',
]
column_editable_list = ['type', 'currency', 'timezone']
......@@ -233,6 +239,7 @@ class UserAdmin(sqla.ModelView):
FilterEqual(column=User.last_name, name='Last Name'),
FilterLastNameBrown(column=User.last_name, name='Last Name',
options=(('1', 'Yes'), ('0', 'No'))),
'phone_number',
'email',
'ip_address',
'currency',
......
......@@ -572,14 +572,20 @@ class ModelView(BaseModelView):
if self.column_searchable_list:
self._search_fields = []
for p in self.column_searchable_list:
attr, joins = tools.get_field_with_path(self.model, p)
for name in self.column_searchable_list:
attr, joins = tools.get_field_with_path(self.model, name)
if not attr:
raise Exception('Failed to find field for search field: %s' % p)
raise Exception('Failed to find field for search field: %s' % name)
for column in tools.get_columns_for_field(attr):
if tools.is_hybrid_property(self.model, name):
column = attr
if isinstance(name, string_types):
column.key = name.split('.')[-1]
self._search_fields.append((column, joins))
else:
for column in tools.get_columns_for_field(attr):
self._search_fields.append((column, joins))
return bool(self.column_searchable_list)
......
......@@ -10,6 +10,7 @@ from flask_admin.contrib.sqla import ModelView, filters, tools
from flask_babelex import Babel
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy import cast
from sqlalchemy_utils import EmailType, ChoiceType, UUIDType, URLType, CurrencyType, ColorType, ArrowType, IPAddressType
from . import setup
......@@ -1559,6 +1560,14 @@ def test_hybrid_property():
def number_of_pixels(self):
return self.width * self.height
@hybrid_property
def number_of_pixels_str(self):
return str(self.number_of_pixels())
@number_of_pixels_str.expression
def number_of_pixels_str(cls):
return cast(cls.width * cls.height, db.String)
db.create_all()
db.session.add(Model1(id=1, name="test_row_1", width=25, height=25))
......@@ -1571,7 +1580,8 @@ def test_hybrid_property():
Model1, db.session,
column_default_sort='number_of_pixels',
column_filters=[filters.IntGreaterFilter(Model1.number_of_pixels,
'Number of Pixels')]
'Number of Pixels')],
column_searchable_list=['number_of_pixels_str', ]
)
admin.add_view(view)
......@@ -1592,6 +1602,13 @@ def test_hybrid_property():
eq_(data[0].name, 'test_row_2')
eq_(data[1].name, 'test_row_1')
# searching
rv = client.get('/admin/model1/?search=100')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test_row_2' in data)
ok_('test_row_1' not in data)
def test_url_args():
app, db, admin = setup()
......
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