Getting CKEditor to work with Flask Admin

放肆的年华 提交于 2019-12-23 01:40:11

问题


I'm trying to make turn the Flask Admin text box into a CKEdit box, as described here. However, when I run it and go to the existing admin fields it doesn't show any change to the text boxes, and when I run it and go to the TestAdmin field created to demonstrate I get this error:

OperationalError: (OperationalError) no such table: test u'SELECT count(?) AS count_1 \nFROM test' ('*',)

Along with a bunch of other traceback messages.

I have changed my init script to be this:

import os
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.login import LoginManager
from flask.ext.openid import OpenID
from flask.ext.mail import Mail
from config import basedir, ADMINS, MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD
from momentjs import momentjs
from flask.ext.babel import Babel
from flask.ext import admin
from flask_admin.contrib.sqla import ModelView
from wtforms import TextAreaField
from wtforms.widgets import TextArea

app = Flask(__name__)

app.config.from_object('config')
db = SQLAlchemy(app)
lm = LoginManager()
lm.init_app(app)
lm.login_view = 'login'
oid = OpenID(app, os.path.join(basedir, 'tmp'))
mail = Mail(app)
babel = Babel(app)

from app import views, models


###
class CKTextAreaWidget(TextArea):
    def __call__(self, field, **kwargs):
        if kwargs.get('class'):
            kwargs['class'] += " ckeditor"
        else:
            kwargs.setdefault('class', 'ckeditor')
        return super(CKTextAreaWidget, self).__call__(field, **kwargs)

class CKTextAreaField(TextAreaField):
    widget = CKTextAreaWidget()


class Test(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.UnicodeText)


class TestAdmin(ModelView):
    form_overrides = dict(text=CKTextAreaField)

    create_template = 'edit.html'
    edit_template = 'edit.html'

admin = admin.Admin(app, name = 'PetroTools', template_mode = 'bootstrap3')
admin.add_view(ModelView(models.Report, db.session))
admin.add_view(ModelView(models.Well, db.session))
admin.add_view(ModelView(models.Field, db.session))
admin.add_view(ModelView(models.Section, db.session))
admin.add_view(TestAdmin(Test, db.session))

if not app.debug:
    import logging
    from logging.handlers import SMTPHandler
    credentials = None
    if MAIL_USERNAME or MAIL_PASSWORD:
        credentials = (MAIL_USERNAME, MAIL_PASSWORD)
    mail_handler = SMTPHandler((MAIL_SERVER, MAIL_PORT), 'no-reply@' + MAIL_SERVER, ADMINS, 'microblog failure', credentials)
    mail_handler.setLevel(logging.ERROR)
    app.logger.addHandler(mail_handler)

if not app.debug:
    import logging
    from logging.handlers import RotatingFileHandler
    file_handler = RotatingFileHandler('tmp/microblog.log', 'a', 1 * 1024 * 1024, 10)
    file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
    app.logger.setLevel(logging.INFO)
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.info('microblog startup')

app.jinja_env.globals['momentjs'] = momentjs

and I've put the edit.html file in my app/templates folder.

My best guess at why it's not working is that maybe I'm not supposed to put edit.html into the templates folder with the other things, but in the flask admin templates folder? But where is that folder? Do I even have one? In edit.html it says:

{% extends 'admin/model/edit.html' %}

But I don't have that directory. Is that what's screwing it up?

I figure I'm probably doing something pretty stupid due to my lack of understanding of how exactly this thing is trying change the ckeditor template. Can anyone help?

Thanks a lot, Alex

Edit: Here is everything in the edit.html file. I haven't edited the version from github, and I have it in the folder /app/templates/.

{% extends 'admin/model/edit.html' %}

{% block tail %}
    {{ super() }}
    <script src="http://cdnjs.cloudflare.com/ajax/libs/ckeditor/4.0.1/ckeditor.js"></script>
{% endblock %}

Final Edit: With Mr Cunningham's help, my final version works and looks like this:

import os
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.login import LoginManager
from flask.ext.openid import OpenID
from flask.ext.mail import Mail
from config import basedir, ADMINS, MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD
from momentjs import momentjs
from flask.ext.babel import Babel

###
from flask.ext import admin
from flask_admin.contrib.sqla import ModelView
from wtforms import TextAreaField
from wtforms.widgets import TextArea
###

app = Flask(__name__)

app.config.from_object('config')
db = SQLAlchemy(app)
lm = LoginManager()
lm.init_app(app)
lm.login_view = 'login'
oid = OpenID(app, os.path.join(basedir, 'tmp'))
mail = Mail(app)
babel = Babel(app)

from app import views, models


###
class CKTextAreaWidget(TextArea):
    def __call__(self, field, **kwargs):
        if kwargs.get('class'):
            kwargs['class'] += " ckeditor"
        else:
            kwargs.setdefault('class', 'ckeditor')
        return super(CKTextAreaWidget, self).__call__(field, **kwargs)

class CKTextAreaField(TextAreaField):
    widget = CKTextAreaWidget()

class TestAdmin(ModelView):
    form_overrides = dict(text=CKTextAreaField)

    create_template = 'edit.html'
    edit_template = 'edit.html'


###ADMIN###
admin = admin.Admin(app, name = 'PetroTools', template_mode = 'bootstrap3')
admin.add_view(TestAdmin(models.Report, db.session))
admin.add_view(TestAdmin(models.Well, db.session))
admin.add_view(TestAdmin(models.Field, db.session))
admin.add_view(TestAdmin(models.Section, db.session))
###########

if not app.debug:
    import logging
    from logging.handlers import SMTPHandler
    credentials = None
    if MAIL_USERNAME or MAIL_PASSWORD:
        credentials = (MAIL_USERNAME, MAIL_PASSWORD)
    mail_handler = SMTPHandler((MAIL_SERVER, MAIL_PORT), 'no-reply@' + MAIL_SERVER, ADMINS, 'microblog failure', credentials)
    mail_handler.setLevel(logging.ERROR)
    app.logger.addHandler(mail_handler)

if not app.debug:
    import logging
    from logging.handlers import RotatingFileHandler
    file_handler = RotatingFileHandler('tmp/microblog.log', 'a', 1 * 1024 * 1024, 10)
    file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
    app.logger.setLevel(logging.INFO)
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.info('microblog startup')

app.jinja_env.globals['momentjs'] = momentjs

At first it still wasn't showing text fields as ckedit fields in admin. I got it to work by dropping all the tables and recreating them, and also using db_migrate.py script from Miguel Grinberg's flask tutorial. I also renamed the text field in my models.py file from Text to text, not sure if that had any effect.


回答1:


Here is a simple working example using in-memory SQLite. There are only two files, the flask application and the edit Jinja2 html template.

Library versions used are Flask 0.10.1, Flask-SQLAlchemy 2.1 and Flask-Admin 1.4.

The flask application flask-ckeditor.py in the root folder:

from flask import Flask
from flask.ext.admin import Admin
from flask.ext.admin.contrib.sqla import ModelView
from flask.ext.admin.menu import MenuLink
from flask.ext.sqlalchemy import SQLAlchemy
from wtforms.widgets import TextArea, TextInput
from wtforms.fields import TextAreaField

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
app.config['SQLALCHEMY_ECHO'] = True
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'super-secret'

db = SQLAlchemy(app)


class Test(db.Model):
    __tablename__ = 'tests'
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.UnicodeText)


class CKEditorWidget(TextArea):
    def __call__(self, field, **kwargs):
        if kwargs.get('class'):
            kwargs['class'] += " ckeditor"
        else:
            kwargs.setdefault('class', 'ckeditor')
        return super(CKEditorWidget, self).__call__(field, **kwargs)


class CKEditorField(TextAreaField):
    widget = CKEditorWidget()


class TestAdminView(ModelView):
    form_overrides = dict(text=CKEditorField)
    can_view_details = True
    create_template = 'edit.html'
    edit_template = 'edit.html'


@app.route('/')
def index():
    return '<a href="/admin/">Click me to get to Admin!</a>'

# Create admin
admin = Admin(app, name='Admin')
admin.add_view(TestAdminView(model=Test, session=db.session, category='Tables', name='Test'))
admin.add_link(MenuLink(name='Public Website', category='', url='/'))


def build_db():

    tests = [
        {
            'text': "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut</p>"
        },
        {
            'text': "<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque<p>"
        },
        {
            'text': "<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium</p>"
        }
    ]

    db.drop_all()
    db.create_all()

    for test in tests:
        test_db = Test(**test)
        db.session.add(test_db)
    db.session.commit()


@app.before_first_request
def create_user():
    build_db()

if __name__ == '__main__':
    app.run(debug=True)

The Jinja2 html template file templates/edit.html:

{% extends 'admin/model/edit.html' %}

{% block tail %}
    {{ super() }}
    <script src="http://cdnjs.cloudflare.com/ajax/libs/ckeditor/4.0.1/ckeditor.js"></script>
{% endblock %}



回答2:


You can use Flask-CKEditor. It provide a CKEditorField that is exactly what you need. We need to install it first:

$ pip install flask-ckeditor

Then in your code:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask_ckeditor import CKEditor, CKEditorField  # Step 1

app = Flask(__name__)
app.config['SECRET_KEY'] = 'dev'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'

db = SQLAlchemy(app)
ckeditor = CKEditor(app)  # Step 2

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120))
    text = db.Column(db.Text)


# Step 3
class PostAdmin(ModelView):
    form_overrides = dict(text=CKEditorField)
    create_template = 'edit.html'
    edit_template = 'edit.html'

admin = Admin(app, name='Flask-CKEditor demo')
admin.add_view(PostAdmin(Post, db.session))

if __name__ == '__main__':
    app.run(debug=True)

In your template (templates/edit.html):

<!-- Step 4 -->
{% extends 'admin/model/edit.html' %}

{% block tail %}
    {{ super() }}
    {{ ckeditor.load() }}
{% endblock %}

Get this demo application on GitHub.



来源:https://stackoverflow.com/questions/34971368/getting-ckeditor-to-work-with-flask-admin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!