Repository: flask-admin/flask-admin

Issue:
column_editable_list do not obey can_edit settings
When ```can_edit = False```, columns in column_editable_list are still editable
column_editable_list do not obey can_edit settings
When ```can_edit = False```, columns in column_editable_list are still editable


Discussion:
Why would you be using `column_editable_list` when `can_edit = False`? While, yes, those columns shouldn't be editable in this case, it doesn't make sense to have `column_editable_list` at all in this scenario.  

~@mrjoes up to you whether or not this issue should be closed.~
For example when `can_edit` is a callback property which returns `True` or `False` depending on current user permissions. And `column_editable_list` is a constant list. In this case (which seems to be very common) ability to edit fields for those users for whom editing was explicitly prohibited could become a big surprise and a security hole.
Or any other case when `can_edit` was true with `column_editable_list`, but then it was set temporarily false in runtime.
Ok, I can see a legitimate use-case when it comes to using a callback for `can_edit`. Can you provide a minimal working example demonstrating this behavior? Once I have that I'll take a look at fixing this.
```python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView


app = Flask(__name__)
app.config.update(
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:',
)

db = SQLAlchemy(app)
admin = Admin(app, url='/')


class Obj(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    description = db.Column(db.String)

class ObjAdmin(ModelView):
    column_editable_list = ['description']

    can_edit = False  #  editing disabled!
    can_delete = False
    can_create = False

admin.add_view(ObjAdmin(Obj, db.session))


@app.before_first_request
def startup():
    db.create_all()
    q = Obj(
        id=1,
        name='test',
        description='try to edit me inplace')
    db.session.add(q)
    db.session.commit()
```
Why would you be using `column_editable_list` when `can_edit = False`? While, yes, those columns shouldn't be editable in this case, it doesn't make sense to have `column_editable_list` at all in this scenario.  

~@mrjoes up to you whether or not this issue should be closed.~
For example when `can_edit` is a callback property which returns `True` or `False` depending on current user permissions. And `column_editable_list` is a constant list. In this case (which seems to be very common) ability to edit fields for those users for whom editing was explicitly prohibited could become a big surprise and a security hole.
Or any other case when `can_edit` was true with `column_editable_list`, but then it was set temporarily false in runtime.
Ok, I can see a legitimate use-case when it comes to using a callback for `can_edit`. Can you provide a minimal working example demonstrating this behavior? Once I have that I'll take a look at fixing this.
```python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView


app = Flask(__name__)
app.config.update(
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:',
)

db = SQLAlchemy(app)
admin = Admin(app, url='/')


class Obj(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    description = db.Column(db.String)

class ObjAdmin(ModelView):
    column_editable_list = ['description']

    can_edit = False  #  editing disabled!
    can_delete = False
    can_create = False

admin.add_view(ObjAdmin(Obj, db.session))


@app.before_first_request
def startup():
    db.create_all()
    q = Obj(
        id=1,
        name='test',
        description='try to edit me inplace')
    db.session.add(q)
    db.session.commit()
```

Resolving patch:
diff --git a/flask_admin/model/base.py b/flask_admin/model/base.py
--- a/flask_admin/model/base.py
+++ b/flask_admin/model/base.py
@@ -1466,7 +1466,7 @@ def is_editable(self, name):
             :param name:
                 Column name.
         """
-        return name in self.column_editable_list
+        return name in self.column_editable_list and self.can_edit
 
     def _get_column_by_idx(self, idx):
         """


Test patch: