Django CMS unable to add a child to a nested plugin - django

For some reason I can't seem to add a child plugin:
I want to achieve the following hierarchy:
Faq row
Faq column
Faq
However when I press the plus sign of the column nothing happens and I am not able to drag the Faq plugin within the Faq column. Any idea?
My plugins definitions:
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from django.utils.translation import ugettext_lazy as _
from .models import FaqPluginModel
class FaqRowPlugin(CMSPluginBase):
name = u'Faq Row'
module = _("Fundbox")
render_template = "faq_row.html"
cache = False
allow_children = True
class FaqColumnPlugin(CMSPluginBase):
name = u'Faq Column'
module = _("Fundbox")
render_template = "faq_column.html"
cache = False
allow_children = True
require_parent = True
class FaqPlugin(CMSPluginBase):
name = u'Faq'
module = _("Fundbox")
model = FaqPluginModel
render_template = "faq.html"
cache = False
plugin_pool.register_plugin(FaqRowPlugin) # register the plugin
plugin_pool.register_plugin(FaqColumnPlugin) # register the plugin
plugin_pool.register_plugin(FaqPlugin) # register the plugin

Related

Adding a String of a filename or absolute path to a database when using Flask-Admin and SQLAlchemy

I am working with SQLAlchemy and Flask-Admin right now. Let us say that I am trying to get a String of the file name or a String of the absolute path of the file name of an image file. I am trying to insert either of these into a database automatically when I create a user. The code that I am using is structured similar to this.  
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
url_pic = Column(String(50), nullable=False)
pic = Column(LargeBinary, nullable=False)
...
from flask.ext.admin.contrib.sqla import ModelView
from flask.ext.admin.form.upload import FileUploadField
from wtforms.validators import ValidationError
from flask.ext.admin import Admin
from flask.ext.sqlalchemy import SQLAlchemy
from flask import Flask
import imghdr
app = Flask(__name__)
db = SQLAlchemy(app)
class UserAdminView(ModelView):
def picture_validation(form, field):
if field.data:
filename = field.data.filename
if filename[-4:] != '.jpg':
raise ValidationError('file must be .jpg')
if imghdr.what(field.data) != 'jpeg':
raise ValidationError('file must be a valid jpeg image.')
field.data = field.data.stream.read()
return True
form_columns = ['id','url_pic', 'pic']
column_labels = dict(id='ID', url_pic="Picture's URL", pic='Picture')
def pic_formatter(view, context, model, name):
return 'NULL' if len(getattr(model, name)) == 0 else 'a picture'
column_formatters = dict(pic=pic_formatter)
form_overrides = dict(pic= FileUploadField)
form_args = dict(pic=dict(validators=[picture_validation]))
admin = Admin(app)
admin.add_view(UserAdminView(User, db.session, category='Database Administration'))
...
How could we get a string version of the file name or absolute path when using the picture_validation function? Right now, the function only provides the binary data of the file, which isn’t as useful.

flask-admin different view for multiple databases

I have two different databases. They are: stock and commodity. Each database has two tables as follows:
Stock: User_trade_stock, stock_prices
Commodity: User_trade_commodity, commodity_prices
I try to build a web app to handle two databases with flask. When I apply flask-admin to them as follows
admin.add_view(UserView(User_trade_stock, db.session))
admin.add_view(UserView(User_trade_commodity, db.session))
I gives the following eror:
Assertion Error: A name collision occurred between blueprints. Blueprints that are created on the fly need unique name.
I tried to add the bind to the db.session as follows
admin.add_view(UserView(User_trade_stock, db.session(bind='stock_bind')))
admin.add_view(UserView(User_trade_commodity, db.session='commodity_bind')))
I got the following error:
scoped session is already present; no new arguments may be specified
Any helps would be appreciated
There are a couple of issues.
Flask-Admin uses a view's lower cased class name for the automatically generated Blueprint name. As you are using UserView twice you have a Blueprint name collision. To overcome this you can specify an endpoint name when you instance a view, for example:
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(TestView(StockTest, db.session, category='Stock', name='Test', endpoint='stock-test'))
admin.add_view(TestView(CommodityTest, db.session, category='Commodity', name='Test', endpoint='commodity-test'))
and to get the urls of the views you would use the following code:
url_for('stock-test.index')
url_for('stock-test.edit')
url_for('commodity-test.index')
url_for('commodity-test.edit')
Secondly, if you want to use the bind feature of Flask-Sqlalchemy you should use the __bind_key__ attribute on the table model, for example:
class User(db.Model):
__bind_key__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
Here is a single file example illustrating both concepts. You will need to run the flask commands flask create-databases and flask populate-databases before you use the app itself. Note I've used a mixin class, TestMixin, to define the model columns.
import click
from flask import Flask
from flask.cli import with_appcontext
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from faker import Faker
from sqlalchemy import Integer, Column, Text
db = SQLAlchemy()
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_BINDS'] = {
'stock': 'sqlite:///stock.db',
'commodity': 'sqlite:///commodity.db'
}
db.init_app(app)
class TestMixin(object):
id = Column(Integer, primary_key=True)
name = Column(Text(), unique=True, nullable=False)
class StockTest(db.Model, TestMixin):
__bind_key__ = 'stock'
class CommodityTest(db.Model, TestMixin):
__bind_key__ = 'commodity'
#click.command('create-databases')
#with_appcontext
def create_databases():
db.drop_all(bind=['stock', 'commodity'])
db.create_all(bind=['stock', 'commodity'])
#click.command('populate-databases')
#with_appcontext
def populate_databases():
_faker = Faker()
db.session.bulk_insert_mappings(StockTest, [{'name': _faker.name()} for _ in range(100)])
db.session.bulk_insert_mappings(CommodityTest, [{'name': _faker.name()} for _ in range(100)])
db.session.commit()
class TestView(ModelView):
pass
app.cli.add_command(create_databases)
app.cli.add_command(populate_databases)
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(TestView(StockTest, db.session, category='Stock', name='Test', endpoint='stock-test'))
admin.add_view(TestView(CommodityTest, db.session, category='Commodity', name='Test', endpoint='commodity-test'))
#app.route('/')
def index():
return 'Click me to get to Admin!'
if __name__ == '__main__':
app.run()

Flask-Migrate - 'Please edit configuratio/connection/logging settings' on 'flask db init'

Have spent literally the past three days trying to figure this out and just can't seem to get it. Have reviewed other posts here and elsewhere regarding the same issue (see here, here, here, among others) countless times and am apparently just too dense to figure it out myself. So here we are, any help would be greatly appreciated.
Project structure:
/project-path/
/app.py
/config.py
/.flaskenv
/app/__init__.py
/app/models.py
/app/routes.py
config.py
import os
from dotenv import load_dotenv
basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir, '.env'))
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'bleh'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
app.py
from app import create_app
app = create_app()
.flaskenv
FLASK_APP=app.py
/app/init.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_marshmallow import Marshmallow
from config import Config
db = SQLAlchemy()
migrate = Migrate()
ma = Marshmallow()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
from app.models import Borrower
db.init_app(app)
migrate.init_app(app, db)
from app.routes import borrowers_api
app.register_blueprint(borrowers_api)
return app
/app/models.py
from app import db, ma
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
class Borrower(db.Model):
__tablename__ = 'borrowers'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
borrower_name = db.Column(db.String(100), nullable=False, unique=True, index=True)
def __init__(self, borrower_name):
self.borrower_name = borrower_name
class BorrowerSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Borrower
include_relationships = True
load_instance = True #Optional: deserialize to model instances
borrower_schema = BorrowerSchema()
borrowers_schema = BorrowerSchema(many=True)
/app/routes.py
from flask import Blueprint, request, jsonify
from app.models import Borrower, borrower_schema, borrowers_schema
from app import db
borrowers_api = Blueprint('borrowers_api', __name__)
# Add a borrower
#borrowers_api.route('/borrower', methods=['POST'])
def add_borrower():
borrower_name = request.get_json(force=True)['borrower_name']
new_borrower = Borrower(borrower_name)
db.session.add(new_borrower)
db.session.commit()
return borrower_schema.jsonify(new_borrower)
# Get single borrower by id
#borrowers_api.route('/borrower/<id>', methods=['GET'])
def get_borrower(id):
borrower = Borrower.query.get(id)
return borrower_schema.jsonify(borrower)
Yet all I continue to run into the following:
(env-name) C:\Users\...\flask-scratchwork\flask-restapi-tryagain>flask db init
Creating directory C:\Users\...\flask-scratchwork\flask-restapi-tryagain\migrations ... done
Creating directory C:\Users\...\flask-scratchwork\flask-restapi-tryagain\migrations\versions ... done
Generating C:\Users\...\flask-scratchwork\flask-restapi-tryagain\migrations\alembic.ini ... done
Generating C:\Users\...\flask-scratchwork\flask-restapi-tryagain\migrations\env.py ... done
Generating C:\Users\...\flask-scratchwork\flask-restapi-tryagain\migrations\README ... done
Generating C:\Users\...\flask-scratchwork\flask-restapi-tryagain\migrations\script.py.mako ... done
Please edit configuration/connection/logging settings in 'C:\\Users\\...\\flask-scratchwork\\flask-restapi-tryagain\\migrations\\alembic.ini' before proceeding.
Where am I going wrong?
Nevermind, think the answer was actually just proceed with flask db migrate despite:
Please edit configuration/connection/logging settings in 'C:\\Users\\...\\flask-scratchwork\\flask-restapi-tryagain\\migrations\\alembic.ini' before proceeding.
So for anyone else spending hours trying to discern precisely what type of edits flask-migrate wants you to make to to the "configuration/connection/logging settings" in alembic.ini...the answer is seemingly to just proceed with flask db migrate

Graphene-Django: In schema combine Query-objects (only takes first argument)

I am trying to combine multiple Query schemas located in different apps in Django 2.1. Using graphene-django 2.2 (have tried 2.1 with same problem). Python 3.7.
The Query class only registers the first variable. As an example shop.schema.Query.
import graphene
import graphql_jwt
from django.conf import settings
import about.schema
import shop.schema
import landingpage.schema
class Query(about.schema.Query, shop.schema.Query, landingpage.schema.Query, graphene.ObjectType):
pass
class Mutation(shop.schema.Mutation, graphene.ObjectType):
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
Why is it like this? Have something changed with classes in python 3.7? The graphene tutorial says this will inherit for multiple...
class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
# This class will inherit from multiple Queries
# as we begin to add more apps to our project
pass
schema = graphene.Schema(query=Query)
I am exporting my schema to schema.json for using it with react relay. I do find my object "collection" Query schema from landingpage(the 3. variable). Relay returns:
ERROR: GraphQLParser: Unknown field collection on type Viewer.
Source: document AppQuery file: containers/App/index.js.
Is it a problem with Relay reading my schema.json?
I managed to solve it shortly after writing this. My problem was that I had a Viewer object in every app. Because I find it useful to have a viewer-graphql-root, like this:
graphql'
viewer {
collection {
somestuff
}
}
'
I moved the Viewer object up to the root schema.py like this:
class Viewer(about.schema.Query, landingpage.schema.Query, shop.schema.Query, graphene.ObjectType):
class Meta:
interfaces = [relay.Node, ]
class Query(graphene.ObjectType):
viewer = graphene.Field(Viewer)
def resolve_viewer(self, info, **kwargs):
return Viewer()
class Mutation(shop.schema.Mutation, graphene.ObjectType):
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
In setting.py add a new file as schema.py
Combine your Queries and Mutations in schema.py as follows:
import graphene
import about.schema as about
import shop.schema as projects
import landingpage.schema as projects
then add:
class Query(about.schema.Query, shop.schema.Query, landingpage.schema.Query, graphene.ObjectType):
pass
class Mutation(about.schema.Mutation, shop.schema.Mutation, landingpage.schema.Mutation, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query, mutation=Mutation)
Configure your combined schema in settings.py as follows:
GRAPHENE = {
"SCHEMA": "core.schema.schema",
}

Django cms accessing extended property

I've extended the Django cms Page model into ExtendedPage model and added page_image to it.
How can I now acces the page_image property in a template.
I'd like to access the page_image property for every child object in a navigation menu... creating a menu with images...
I've extended the admin and I have the field available for editing (adding the picture)
from django.db import models
from django.utils.translation import ugettext_lazy as _
from cms.models.pagemodel import Page
from django.conf import settings
class ExtendedPage(models.Model):
page = models.OneToOneField(Page, unique=True, verbose_name=_("Page"), editable=False, related_name='extended_fields')
page_image = models.ImageField(upload_to=settings.MEDIA_ROOT, verbose_name=_("Page image"), blank=True)
Thank you!
BR
request.current_page.extended_fields.page_image
should work if you are using < 2.4. In 2.4 they introduced a new two page system (published/draft) so you might need
request.current_page.publisher_draft.extended_fields.page_image
I usually write some middleware or a template processor to handle this instead of doing it repetitively in the template. Something like:
class PageOptions(object):
def process_request(self, request):
request.options = dict()
if not request.options and request.current_page:
extended_fields = None
try:
extended_fields = request.current_page.extended_fields
except:
try:
custom_settings = request.current_page.publisher_draft.extended_fields
except:
pass
if extended_fields:
for field in extended_fields._meta.fields:
request.options[field.name] = getattr(extended_fields, field.name)
return None
will allow you to simply do {{ request.options.page_image }}