Using Flask Restful as a Blueprint in Large Application - flask

I am trying to use Flask restful as a Blueprint in a pattern that works for other blueprints. I keep getting the following error message
I get the following error message
AttributeError: 'Blueprint' object has no attribute 'add_resource'
My project setup is as follows:
Folder structure
├── app
│   ├── __init__.py
│   ├── api
│   │   ├── __init__.py
│   │   └── routes.py
│   ├── main
│   │   ├── __init__.py
│   │   ├── forms.py
│   │   └── views.py
│   └── templates
│   ├── base.html
│   └── home.html
├── config.py
├── manage.py
└── requirements.txt
__init__.py
from flask import Flask
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config
bootstrap = Bootstrap()
api = Api()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
api.init_app(app)
from .main import main as main_blueprint
from .api import api as api_blueprint
app.register_blueprint(main_blueprint)
app.register_blueprint(api_blueprint)
return app
api/__init__.py
from flask import Blueprint
api = Blueprint('api', __name__)
from . import routes
api/routes.py
from flask_restful import Resource
from . import api
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
What am I doing wrong??

If you follow the instructions from https://flask-restful.readthedocs.io/en/0.3.5/intermediate-usage.html
The key points here are to create a Flask Blueprint instance & pass it to a new instance of flask-restfuls's Api class.
Lastly, make sure to register the flask-restful api blueprint within your create_app function: app.register_blueprint(api_bp)
from flask import Flask, Blueprint
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config
bootstrap = Bootstrap()
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
from .users import main as users_blueprint
from .blogs import main as blogs_blueprint
# blueprints for blogs & users
app.register_blueprint(users_blueprint)
app.register_blueprint(blogs_blueprint)
app.register_blueprint(api_bp)
return app
Also note, you don't need to register api.init_app(app) anymore.

You're running in to trouble because of how you've named your blueprint api, whilst also using the api object from flask_restful. In your routes.py you're explicitly importing api from api/__init__.py, and this is a Blueprint object. You can't call add_resource to a Blueprint object, only to an Api object from flask_restful.
If you change your import to:
from .. import api
you'll be importing the correct object. I'd still recommend changing your blueprint name anyway to avoid this sort of confusion.

If you want to have submodules (like your /api) based on resources...
Eg: folder structure
├── app
│ ├── __init__.py
│ ├── foo
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── boo
│ │ ├── __init__.py
│ │ └── routes.py
├── config.py
├── manage.py
... and register their blueprints with url_prefix to not repeat the common part in each added resource. Create new Api instance in each module and pass to it a blueprint.
foo/__init__.py
from flask import Blueprint
from flask_restful import Api
foo_bp = Blueprint('foo', __name__, url_prefix='/foo')
foo_api = Api(foo_bp)
from . import routes
in routes import foo_api and add resources to it
foo/routes.py
from flask_restful import Resource
from . import foo_api
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
foo_api.add_resource(TodoItem, '/todos/<int:id>')
Then in main application __init__.py just import modules blueprints and register it. You dont even need to add a "main" application blueprint. If you would import the api from main application __init__ then you can't register each blueprint with it's own params like url_prefix.
__init__.py
from flask import Flask
from config import config
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
from .foo import foo_bp
from .boo import boo_bp
app.register_blueprint(foo_bp)
app.register_blueprint(boo_bp)
return app
You can set the url_prefix on register blueprint (it has priority) or when you create it. To check routes you can print the app.url_map

Related

Adding dash to flask app where dash need to access db and user session_id

I have a flask app with the following structure:
/test
├── /application
│ ├── __init__.py
│ ├── routes.py
│ ├── /static
│ ├── /templates
│ └── /dashboard
│ └── __init__.py
├── db.py
├── config.py
├── requirements.txt
├── helpers.py
└── wsgi.py
I am trying to implement a dash dashboard by intitating it through calling a function in application.init.py
where the function is define in dashboard.init.py
my application.init.py
def init_app():
"""Construct core Flask application."""
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.Config')
# Ensure responses aren't cached
#app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
# Custom filter
app.jinja_env.filters["usd"] = usd
Session(app)
assets = Environment()
assets.init_app(app)
with app.app_context():
# Import parts of our core Flask app
from . import routes
from .assets import compile_static_assets
# Import Dash application
from .dashboard import init_dashboard
app = init_dashboard(app)
# Compile static assets
compile_static_assets(assets)
return app
in dashboard.init.py file the function init_dashboard need to access the database and the user id, because the dashboard layout need to use values from the database so that it will show the specific dashboard for the user, but of course this does not work as it return the error "Working outside of request context".
If I will try to create the dashboard in routes for example:
#app.route("/dashapp/")
#login_required
def redirect_to_dashapp():
dash_app = dash.Dash(
server=app,
routes_pathname_prefix="/dashapp/")
"""Create a Plotly Dash dashboard."""
stocks = db.session.query(Records.symbol, Records.number_of_shares, Records.purchase_p, Records.execution_time).filter_by(user_id=session["user_id"]).all()
.....
it will return the error "A setup function was called after the first request was handled. "
As the dash layout need values from the database I can't initiate it in init_dashboard() without accessing the db, and I can't initiate in routes either.
Does anyone has a suggestion on how to properly do it?

How to defined a database connecting Flask python file and then import it?

1.I was trying to use Pymongo to connect to my MongoDB atlas database. I wrote this file into the connect.py file. Here is the tree folder structure. The connect.py contains the URL information to connect the database.
└── uploading
├── __pycache__
│   └── upload.cpython-38.pyc
└── upload.py
├── Database
│   ├── __pycache__
│   │   └── connect.cpython-38.pyc
│   └── connect.py
├── app.py
2.Here is code for connect.py
import pymongo
client = pymongo.MongoClient("URL",ssl=True, ssl_cert_reqs='CERT_NONE')
db = client.datasets
Here is the code for uplod.py
from flask import Blueprint, current_app
from Database.connect import db
sample = Blueprint('sample', __name__)
#sample.route('/')
def index():
x = current_app.config['UPLOAD_PATH']
return str(db)
Here is the code for app.py:
app = Flask(__name__)
app.secret_key = b'pj&\xe9\xd7\xd7\xabc\xe6KX\xbe\x9f<\x9f\x87'
app.config['UPLOAD_PATH'] = 'public' # to create a folder which is used to save the uploaded file
CORS(app)
app.register_blueprint(sample)
'''
Datasets and model upload
'''
#app.route('/connect-upload', methods=["POST"])
#cross_origin()
def connect_upload():
index=0
# get username
return "result"
When I tried to use : from Database.connect import db to import database in the upload.py, it showed error message :ImportError: cannot import name 'db' from 'Database.connect'. How can I solve this problem?
You are not referencing your module correctly. Your module should be the filename. You should use from connect import db.

pre_delete signal not working in specific directory

i want remove file from storage when a File instance removed.trying to use django signal. here is my model File:
class File(models.Model):
orig_name = models.CharField(_('Original Name'), max_length=255)
conversation = models.ForeignKey('conversation.Conversation', on_delete=models.CASCADE)
the architecture of every app are same.means all of app have own signals directory and in signals's directory we have __init__.py and handlers.py files .here is a brief tree of my app with some detail for file's app:
apps
├── conversation
├── post
└── file
├── admin.py
├── apps.py
├── __init__.py
├── models.py
├── signals
│   ├── handlers.py
│   └── __init__.py
├── tests.py
├── urls.py
└── views.py
here is apps/file/apps.py:
from django.apps import AppConfig
class FileConfig(AppConfig):
name = 'apps.file' # exact as INSTALLED_APP in setting.py
def ready(self):
import apps.file.signals.handers
here is apps/file/signals/handlers.py :
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from apps.file.models import File
#receiver(pre_delete, sender=File)
def remove_file_from_storage(sender, instance, *args, **kwargs):
print('pre_delete signal for File working')
# some code is here
and app/file/signals/__init__.py file is empty. in this project we are using multiple signals and all of them working fine but i don't know why this signal not working.other signal are from custom and build-in signal both. please notice when i moving def remove_file_from_storage function into other app into related app_name/signals/handlers.py it's working fine.the process of deleting is a simple generics.DestroyAPIView of DRF. where is the problem with my architect of using signal?thank you
The problem is because you use receiver decorator to register signals. With that you have to place your code inside ready function of your Django application. This document does mention about that:
In practice, signal handlers are usually defined in a signals submodule of the application they relate to. Signal receivers are connected in the ready() method of your application configuration class. If you’re using the receiver() decorator, simply import the signals submodule inside ready().
But in real practice, we won't put all signals code inside ready method, that might make our code harder to read and harder to maintain. So like you did, we will put the signals inside signals.py and then load it into your app via ready method, like so:
from django.apps import AppConfig
class FileConfig(AppConfig):
label = 'file'
name = 'file'
def ready(self):
from apps.file import signals # NOQA
# add # NOQA to ignore error message from Python linter when we just import but never used
and set this to __init__.py so that Django could discover your app:
apps
├── conversation
├── post
└── file
├── admin.py
├── apps.py
├── __init__.py # Add to this file
├── models.py
├── signals
│ ├── handlers.py
│ └── __init__.py
├── tests.py
├── urls.py
└── views.py
default_app_config = 'apps.file.apps.FileConfig'
You could also take a look at this article to gain more details about Django signals
Hope that helps!

Unittesting an app

I'm trying to run a simple unit-test for a restful app I'm creating. The server runs perfectly and displays the json data. I'm looking for a test that confirms that the json data is a 'GET' request or confirms a say a 200 response status code
below is my directory structure
├── MealAPP
├── app
│ ├── __init__.py
│ └── models.py
├── instance
│ ├── __init__.py
│ └── config.py
├── manage.py
├── requirements.txt
├── run.py
└── test_mealapp.py
init.py
from flask_api import FlaskAPI
from flask_sqlalchemy import SQLAlchemy
from flask import Flask, jsonify, request
# local import
from instance.config import app_config
# initialize sql-alchemy
db = SQLAlchemy()
def create_app(config_name):
app = FlaskAPI(__name__, instance_relative_config=True)
app.config.from_object(app_config["development"])
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
#app.route("/", methods=['GET'])
def test():
return jsonify({'message':'It works!'})
return app
test_mealapp.py
import unittest
import os
import json
from app import create_app
class FlaskTestCase(unittest.TestCase):
def test_index(self):
"""Define test variables and initialize app."""
self.app = create_app(config_name="testing")
self.client = app.client.test_client
response = self.client("/")
# self.assertEqual(response[message],"It works!")
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
Any tips on how to fix my test_mealapp.py?
This would work:
class FlaskTestCase(unittest.TestCase):
def test_index(self):
self.app = create_app(config_name="testing")
with self.app.test_client() as client:
response = client.get("/")
responseJson = json.loads(response.data)
self.assertEqual(responseJson['message'], "It works!")
self.assertEqual(response.status_code, 200)
Try to always use the client in a with: block and make sure to use the request method as the attribute to client (get in this case)

django cannot find management command

I am using django 1.5.1 and trying to get moving the management command. I have an app called patient and here is the directory structure.
patient/
├── __init__.py
├── forms.py
├── management
│   ├── __init.py__
│   └── commands
│   ├── __init.py__
│   └── recall1.py
├── models.py
├── urls.py
├── views.py
Here is what happens when I try to run the recall1 command:
$ python manage.py recall1
Unknown command: 'recall1'
Here is how my code looks like:
from django.core.management.base import BaseCommand, CommandError
from recall.model import PatientRecalls, RecallType, RecallMessage
from patient.model import Patient
class Command(BaseCommand):
args = '<patient_id patient_id ...>'
def handle(self, *args, **options):
for patient_id in args:
try:
patient = Patient.objects.get(pk=int(patient_id))
except Patient.DoesNotExist:
raise CommandError('Patient "%s" does not exist' % patient_id)
patient.opened = False
patient.save()
self.stdout.write('Successfully closed patient "%s"' % patient_id)
What wrong do I need to correct before I can run this thing? The app is running great, except for this issue..
Your filename __init.py__ should actually be __init__.py both in the directories management/ and commands/