0

I have an issue, I have created a command in my project for creating the database, my issue is that I would like to move it and other simmilar things to seperate files, but if I try to import them from a different file I get an import error, could anyone help me resolve this issue, thank you. This is my application.py file.

import flask

from database_website.extensions.database import db
from database_website.properties import navigation_bar


class Application(flask.Flask):
    def load_configuration(self):
        self.config.from_pyfile('configuration.py')

    def configure_database(self):
        from database_website.extensions.database import db

        db.init_app(app=self)

    def configure_login_manager(self):
        from database_website.extensions.auth import login_manager

        login_manager.init_app(app=self)

    def register_applications(self):
        from database_website.applications.core.urls import blueprint as core_blueprint
        from database_website.applications.users.urls import blueprint as users_blueprint
        from database_website.applications.products.urls import blueprint as products_blueprint

        self.register_blueprint(blueprint=users_blueprint)
        self.register_blueprint(blueprint=products_blueprint)
        self.register_blueprint(blueprint=core_blueprint)

    @classmethod
    def create(cls):
        instance = Application(__name__)

        instance.load_configuration()
        instance.configure_database()
        instance.configure_login_manager()
        instance.register_applications()

        return instance


application = Application.create()


@application.cli.command()
def create_database():
    db.create_all()


def has_no_empty_params(rule):
    defaults = rule.defaults if rule.defaults is not None else ()
    arguments = rule.arguments if rule.arguments is not None else ()
    return len(defaults) >= len(arguments)


def sitemap():
    links = []
    for rule in application.url_map.iter_rules():
        # Filter out rules we can't navigate to in a browser
        # and rules that require parameters
        if "GET" in rule.methods and has_no_empty_params(rule):
            url = flask.url_for(rule.endpoint, **(rule.defaults or {}))
            links.append((url, rule.endpoint))
    return links


@application.context_processor
def inject_endpoints():
    return dict(endpoints=sitemap())


@application.context_processor
def inject_navigation():
    return dict(nav_bar=navigation_bar)


application.run()

And things I want to move would be the injects and the command.

My application.py file after editing and moving the command to a commands.py file.

mport flask

from flask_migrate import Migrate

from database_website.extensions.database import db
from database_website.properties import navigation_bar
from database_website.commands import create_database


class Application(flask.Flask):
    def create_migrations(self):
        migrate = Migrate(self, db)

    def load_configuration(self):
        self.config.from_pyfile('configuration.py')

    def configure_database(self):
        from database_website.extensions.database import db

        db.init_app(app=self)

    def configure_login_manager(self):
        from database_website.extensions.auth import login_manager

        login_manager.init_app(app=self)

    def register_applications(self):
        from database_website.applications.core.urls import blueprint as core_blueprint
        from database_website.applications.users.urls import blueprint as users_blueprint
        from database_website.applications.products.urls import blueprint as products_blueprint

        self.register_blueprint(blueprint=users_blueprint)
        self.register_blueprint(blueprint=products_blueprint)
        self.register_blueprint(blueprint=core_blueprint)

    @classmethod
    def create(cls):
        instance = Application(__name__)

        instance.load_configuration()
        instance.configure_database()
        instance.configure_login_manager()
        instance.register_applications()
        instance.create_migrations()

        return instance


application = Application.create()


def has_no_empty_params(rule):
    defaults = rule.defaults if rule.defaults is not None else ()
    arguments = rule.arguments if rule.arguments is not None else ()
    return len(defaults) >= len(arguments)


def sitemap():
    links = []
    for rule in application.url_map.iter_rules():
        # Filter out rules we can't navigate to in a browser
        # and rules that require parameters
        if "GET" in rule.methods and has_no_empty_params(rule):
            url = flask.url_for(rule.endpoint, **(rule.defaults or {}))
            links.append((url, rule.endpoint))
    return links


@application.context_processor
def inject_endpoints():
    return dict(endpoints=sitemap())


@application.context_processor
def inject_navigation():
    return dict(nav_bar=navigation_bar)


application.run()

The traceback:

Traceback (most recent call last):
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\application.py", line 7, in <module>
    from database_website.commands import create_database
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\commands.py", line 1, in <module>
    from database_website.application import application
  File "C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\application.py", line 7, in <module>
    from database_website.commands import create_database
ImportError: cannot import name 'create_database' from 'database_website.commands' (C:\Users\ulman\PycharmProjects\database_website_optimised\source\database_website\commands.py)

I moved the command over to a commands file and then imported it into the application file.

MareksNo
  • 140
  • 2
  • 12

1 Answers1

1

Edited:

I haven't ran this myself but something like this should point you in the right direction. You should be able to register your commands blueprint just like the other blueprints you are already registering.

commands.py

from flask import Blueprint

from database_website.extensions.database import db

blueprint = Blueprint('commands_blueprint', __name__)

@commands_blueprint.cli.command()
def create_database():
    db.create_all()

applications.py

import flask

from database_website.extensions.database import db
from database_website.properties import navigation_bar

class Application(flask.Flask):
    ...
    def register_applications(self):
        from database_website.applications.core.urls import blueprint as core_blueprint
        from database_website.applications.users.urls import blueprint as users_blueprint
        from database_website.applications.products.urls import blueprint as products_blueprint
        from database_wensite.commands import blueprint as commands_blueprint

        self.register_blueprint(blueprint=users_blueprint)
        self.register_blueprint(blueprint=products_blueprint)
        self.register_blueprint(blueprint=core_blueprint)
        self.register_blueprint(blueprint=commands_blueprint)
    ...

You can use flask blueprints to help make your code more modular.

https://flask.palletsprojects.com/en/1.1.x/blueprints/

Where should I implement flask custom commands (cli)

  • I am using blueprints, but if I understand correctly, I can make the cli commands inside of the blueprint?(But the problem witht hat is tat in my case create-database command is not specific to a blueprint) – MareksNo Jul 01 '20 at 13:18
  • What does your code look like after you refactor and what error do you receive? – Steffen Andersland Jul 01 '20 at 13:44
  • Will add to my edit, edit: added to my original post, the way is janky, but without importing back in itwould not get read. You mentioned blueprints, so could I create a "Commands" blueprint for just commands? Or maybe there is a better way – MareksNo Jul 01 '20 at 16:23
  • I've updated my answer, please try to register your commands blueprint just like you might any other blueprint. NOTE: I don't know your project folder structure so be aware of imports – Steffen Andersland Jul 01 '20 at 18:40
  • Thank you, it works on the commands part, but trying something like that on the injects made the injected objectbe undefined. I tried also using it as properties.nav_bar instead of just nav_bar in my template but that didnt seem to change anything. Maybe I am reffering to t incorrectly as when building the project, no errors were in sight – MareksNo Jul 02 '20 at 13:52
  • 1
    Upadte, found somewhere an answer to my question, turns out that istead of context_Processor I should use app_context_Processor – MareksNo Jul 02 '20 at 13:56
  • Not quite sure about the difference between the 2 but if you know it, I would be happy to know it too :) Thanks again, for your help – MareksNo Jul 02 '20 at 14:02