Commit 54781df2 authored by Eric Régnier's avatar Eric Régnier
parents 681dce63 f04b71b7
...@@ -33,6 +33,10 @@ matrix: ...@@ -33,6 +33,10 @@ matrix:
addons: addons:
postgresql: "9.4" postgresql: "9.4"
apt:
packages:
- postgresql-9.4-postgis-2.4
- postgresql-9.4-postgis-2.4-scripts
services: services:
- postgresql - postgresql
......
...@@ -14,8 +14,8 @@ def parse_like_term(term): ...@@ -14,8 +14,8 @@ def parse_like_term(term):
def get_meta_fields(model): def get_meta_fields(model):
try: if hasattr(model._meta, 'sorted_fields'):
fields = model._meta.sorted_fields fields = model._meta.sorted_fields
except AttributeError: else:
fields = model._meta.get_fields() fields = model._meta.get_fields()
return fields return fields
...@@ -2,18 +2,18 @@ import logging ...@@ -2,18 +2,18 @@ import logging
from flask import flash from flask import flash
from flask_admin._compat import string_types, iteritems from flask_admin._compat import string_types
from flask_admin.babel import gettext, ngettext, lazy_gettext from flask_admin.babel import gettext, ngettext, lazy_gettext
from flask_admin.model import BaseModelView from flask_admin.model import BaseModelView
from flask_admin.model.form import create_editable_list_form from flask_admin.model.form import create_editable_list_form
from peewee import PrimaryKeyField, ForeignKeyField, Field, CharField, TextField from peewee import JOIN, PrimaryKeyField, ForeignKeyField, Field, CharField, TextField
from flask_admin.actions import action from flask_admin.actions import action
from flask_admin.contrib.peewee import filters from flask_admin.contrib.peewee import filters
from .form import get_form, CustomModelConverter, InlineModelConverter, save_inline from .form import get_form, CustomModelConverter, InlineModelConverter, save_inline
from .tools import get_primary_key, parse_like_term from .tools import get_meta_fields, get_primary_key, parse_like_term
from .ajax import create_ajax_loader from .ajax import create_ajax_loader
# Set up logger # Set up logger
...@@ -176,7 +176,9 @@ class ModelView(BaseModelView): ...@@ -176,7 +176,9 @@ class ModelView(BaseModelView):
if model is None: if model is None:
model = self.model model = self.model
return iteritems(model._meta.fields) return (
(field.name, field)
for field in get_meta_fields(model))
def scaffold_pk(self): def scaffold_pk(self):
return get_primary_key(self.model) return get_primary_key(self.model)
...@@ -309,7 +311,7 @@ class ModelView(BaseModelView): ...@@ -309,7 +311,7 @@ class ModelView(BaseModelView):
model_name = field.model_class.__name__ model_name = field.model_class.__name__
if model_name not in joins: if model_name not in joins:
query = query.join(field.model_class) query = query.join(field.model_class, JOIN.LEFT_OUTER)
joins.add(model_name) joins.add(model_name)
return query return query
......
...@@ -276,7 +276,7 @@ class InlineModelFormList(InlineFieldList): ...@@ -276,7 +276,7 @@ class InlineModelFormList(InlineFieldList):
# Handle request data # Handle request data
for field in self.entries: for field in self.entries:
field_id = field.get_pk() field_id = str(field.get_pk())
is_created = field_id not in pk_map is_created = field_id not in pk_map
if not is_created: if not is_created:
......
...@@ -264,7 +264,7 @@ class AdminModelConverter(ModelConverterBase): ...@@ -264,7 +264,7 @@ class AdminModelConverter(ModelConverterBase):
@classmethod @classmethod
def _string_common(cls, column, field_args, **extra): def _string_common(cls, column, field_args, **extra):
if isinstance(column.type.length, int) and column.type.length: if hasattr(column.type, 'length') and isinstance(column.type.length, int) and column.type.length:
field_args['validators'].append(validators.Length(max=column.type.length)) field_args['validators'].append(validators.Length(max=column.type.length))
@converts('String') # includes VARCHAR, CHAR, and Unicode @converts('String') # includes VARCHAR, CHAR, and Unicode
...@@ -290,7 +290,7 @@ class AdminModelConverter(ModelConverterBase): ...@@ -290,7 +290,7 @@ class AdminModelConverter(ModelConverterBase):
self._string_common(column=column, field_args=field_args, **extra) self._string_common(column=column, field_args=field_args, **extra)
return fields.StringField(**field_args) return fields.StringField(**field_args)
@converts('Text', 'LargeBinary', 'Binary') # includes UnicodeText @converts('Text', 'LargeBinary', 'Binary', 'CIText') # includes UnicodeText
def conv_Text(self, field_args, **extra): def conv_Text(self, field_args, **extra):
self._string_common(field_args=field_args, **extra) self._string_common(field_args=field_args, **extra)
return fields.TextAreaField(**field_args) return fields.TextAreaField(**field_args)
......
...@@ -75,14 +75,14 @@ def tuple_operator_in(model_pk, ids): ...@@ -75,14 +75,14 @@ def tuple_operator_in(model_pk, ids):
The returning operator can be used within a filter(), as it is just an or_ operator The returning operator can be used within a filter(), as it is just an or_ operator
""" """
l = [] ands = []
for id in ids: for id in ids:
k = [] k = []
for i in range(len(model_pk)): for i in range(len(model_pk)):
k.append(eq(model_pk[i], id[i])) k.append(eq(model_pk[i], id[i]))
l.append(and_(*k)) ands.append(and_(*k))
if len(l) >= 1: if len(ands) >= 1:
return or_(*l) return or_(*ands)
else: else:
return None return None
......
...@@ -4,6 +4,7 @@ from . import setup_postgres ...@@ -4,6 +4,7 @@ from . import setup_postgres
from .test_basic import CustomModelView from .test_basic import CustomModelView
from sqlalchemy.dialects.postgresql import HSTORE, JSON from sqlalchemy.dialects.postgresql import HSTORE, JSON
from citext import CIText
def test_hstore(): def test_hstore():
...@@ -75,3 +76,39 @@ def test_json(): ...@@ -75,3 +76,39 @@ def test_json():
data = rv.data.decode('utf-8') data = rv.data.decode('utf-8')
ok_('json_test' in data) ok_('json_test' in data)
ok_('>{"test_key1": "test_value1"}<' in data) ok_('>{"test_key1": "test_value1"}<' in data)
def test_citext():
app, db, admin = setup_postgres()
class CITextModel(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
citext_test = db.Column(CIText)
db.engine.execute('CREATE EXTENSION IF NOT EXISTS citext')
db.create_all()
view = CustomModelView(CITextModel, db.session)
admin.add_view(view)
client = app.test_client()
rv = client.get('/admin/citextmodel/')
eq_(rv.status_code, 200)
rv = client.post('/admin/citextmodel/new/', data={
'citext_test': 'Foo',
})
eq_(rv.status_code, 302)
rv = client.get('/admin/citextmodel/')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('citext_test' in data)
ok_('Foo' in data)
rv = client.get('/admin/citextmodel/edit/?id=1')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('name="citext_test"' in data)
ok_('>Foo<' in data)
...@@ -14,3 +14,4 @@ psycopg2 ...@@ -14,3 +14,4 @@ psycopg2
nose nose
coveralls coveralls
pylint pylint
sqlalchemy-citext
...@@ -8,7 +8,7 @@ skip_missing_interpreters = true ...@@ -8,7 +8,7 @@ skip_missing_interpreters = true
[flake8] [flake8]
max_line_length = 120 max_line_length = 120
ignore = E402 ignore = E402,E722
[testenv] [testenv]
usedevelop = true usedevelop = true
......
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