Import a django app view in another app view - django

I have two django apps and I've called a view of app1 in app2, like this:
#app: app1
#someview.py
def a_view(request, someparam):
#some code here
#app: app2
#otherview.py
from app1.someview import a_view
def another_view(request):
param = 1
a_view(request, param)
def view2(request):
#some code
It works fine. My problem is that now I want to call a view from app2 in app1. So I add the import statement in someview.py like this:
#app: app1
#someview.py
from app2.otherview import view2
def a_view(request, someparam):
#some code here
The result is an ImportError "cannot import name view2".
Can anyone tell me why this happen?

The second import shadowing the first one ... Try like
import app2.otherview
or
from app2.views as app2_views

You can't do this because makes a loop.
You must add functions in another file and import in app1 and app2 separately.

Related

Securing Flask-Admin When Using Blueprints and Application Factory

I've set up Flask Admin and it is working, but am struggling with adding authentication. There are several tutorials I've followed but can't seem to get them to work with how I've set up my app. Per the documentation on Flask-Admin regarding authentication (and slightly tweaked based on how I'm importing various elements), you just need to add:
class AdminView(ModelView):
def is_accessible(self):
return current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
# redirect to login page if user doesn't have access
return redirect(url_for('login', next=request.url))
But I can still access the /admin route without logging in. (I also would like to add an additional conditional that checks that the user is listed as an admin, which is a boolean column in the user table, but I haven't gotten this first part to work).
I've tried putting the above inside and outside of the create_app() function. Does this have to do with my blueprints? If so, where would I put this code?
# __init__.py
from flask import Flask
from dotenv import load_dotenv
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager, current_user
from flask_migrate import Migrate
from SIMS_Portal.config import Config
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flaskext.markdown import Markdown
load_dotenv()
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'danger'
mail = Mail()
from SIMS_Portal import models
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
bcrypt.init_app(app)
login_manager.init_app(app)
mail.init_app(app)
admin = Admin(app, name='SIMS Admin Portal', template_mode='bootstrap4', endpoint='admin')
Markdown(app)
from SIMS_Portal.main.routes import main
from SIMS_Portal.assignments.routes import assignments
from SIMS_Portal.emergencies.routes import emergencies
from SIMS_Portal.portfolios.routes import portfolios
from SIMS_Portal.users.routes import users
from SIMS_Portal.errors.handlers import errors
app.register_blueprint(main)
app.register_blueprint(assignments)
app.register_blueprint(emergencies)
app.register_blueprint(portfolios)
app.register_blueprint(users)
app.register_blueprint(errors)
from SIMS_Portal.models import User, Assignment, Emergency, Portfolio, NationalSociety
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Assignment, db.session))
admin.add_view(ModelView(Emergency, db.session))
admin.add_view(ModelView(Portfolio, db.session))
admin.add_view(ModelView(NationalSociety, db.session))
return app
Got some help from the r/flask community which I'll share here for anyone else that has set their app up the same way and found existing tutorials unhelpful. The key when using an app factory like in my case is the swap out the ModelView for the AdminView you define, which can go before the create_app() function. In my __init__.py, I first defined that custom class that inherits from ModelView (and add a check that the user is not only logged in but also listed as an admin in my database):
class AdminView(ModelView):
def is_accessible(self):
if current_user.is_admin == 1:
return current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
return render_template('errors/403.html'), 403
Then within the create_app() I swap out what I had previously included as admin.add_view(ModelView(User, db.session)) for admin.add_view(AdminView(User, db.session))
That little difference makes obvious sense, but again, I couldn't find tutorials that covered this.

Flask set #app decorator outside main module

How do you set an #app... decorator outside of the main module?
I'm sorry if this a dumb question, but I am completely lost.
I wish to be able to decorate functions with #app.context_processor all over the place in a larg-ish app. All the examples I can find have these in main module, where app is defined. Thus in main.py I have e.g.
from app import create_app
app = create_app()
#app.context_processor
def test_me():
return {'test_me': 'test_me!!!'}
and in __init__.py I have
def create_app(config_class=Config):
app = Flask(__name__)
return app
That's fine, but how do I do same in some other module? app is not defined.
Let's say I have just that def test_me() in some other module. The module (presently) has no imports, doesn't use blueprints, etc.
Most questions asking about "how to access app in another module" use from flask import current_app, but you can only use current_app during a request, such as inside a def. Attempting to somehow use it for a decorator will give you the "not available in this context`, so that's not the way to go.
To answer my own question.
I needed to move the
app = create_app()
out of main.py and into __init__.py. Then app is visible to every module, and each one can go
from app import app
#app.context_processor
def something():
return {'something': 'something'}

Django signals not working for my directory structure

I am trying to implement signals for my app and my directory structure looks like this
- src
- utility_apps
__init__.py
- posts
- migrations
- static
- templates
admin.py
views.py
apps.py
signals.py
models.py
__init__.py
......
static
manage.py
......
Here posts is my app and the signals.py is inside its folder, But my signals aren't working.
I have defined my signal code as -
from .models import Post
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Post)
def give_group_owner_permission(sender, instance, created, **kwargs):
print("coming to signal")
if created:
print("created")
But it doesn't work. In my apps.py I have changed the ready function as
class Post(AppConfig):
name = 'post'
def ready(self):
import utility_apps.posts.signals
I have even tried importing posts.signal in the ready function. What I am doing wrong here, please help
My installed apps look like below
INSTALLED_APPS = [
'utility_apps.posts',
'mainapp',
.....
]
The following solution worked for me.
The first change which I had to make was put a default_app_config value in my __init__.py file of my posts app as
default_app_config = 'utility_apps.posts.apps.PostsConfig'
And then I had to change PostsConfig class as
class PostsConfig(AppConfig):
name = 'utility_apps.posts'
def ready(self):
import utility_apps.posts.signals
Basically I had to change two things -
The name which was set to posts by default
Change the ready function and import my signals in it
It worked for me.
Alternatively, I could have also included my PostsConfig in my installed app.

Django signal receiving across apps

I have a main_app, and app2. main_app is essentially a list of items with data, and app2 has more information about said items.
main_app isn't supposed to know about app2, but app2 can import from main_app.
Within main_app/signals.py, I have
import django.dispatch
mysignal = django.dispatch.Signal(providing_args=['uid'])
In main_app/views.py, I have a view which renders various main_templates, containing the details of the item, a view for editing, and one for submitting said edited data. The idea is that a signal is sent when each of those is called and, app2 receives this. main_template uses the "with" call to get template2 and that app's information.
In app2/processes.py I have the following:
import django.dispatch
from django.dispatch import receiver
import my models
from main_app.signals import mysignal, (mysignal2, etc)
Then for each method, I have
#receiver(mysignal)
def foo(sender, **kwargs) etc
OK... So, in main_app/views.py, if I have the line:
from app2.processes import mysignal, mysignal2 etc
Everything works smoothly. But I want to remove any reliance on app2 in main_app. As far as I am concerned, app2 is just importing these signals from main_app/signals.py.
But if I try to get rid of the above line and put the following into main_app/views.py
from main_app.processes import mysignal, my...
It doesn't work...I don't get an error but the data from app2 doesn't render into the template, and I really don't see why....Any ideas?
Your signal receivers in app2 are probably not registered. Simple check: put raise Exception("I was imported!"); as the first line in app2/processes.py. You probably will never see that exception. You will have to make sure the signal receivers are being registered. You can do this by import app2.processes somewhere Django will look. For example in app2/models.py.

dajaxice.core.js not updated with functions in ajax.py

I'm running Django (1.4.3) with dajaxice (0.5.4). I have a file ajax.py with my functions in the main project folder called prj, which looks like:
from dajax.core import Dajax
from dajaxice.decorators import dajaxice_register
from django.utils import simplejson
from dajaxice.core import dajaxice_functions
from django.core.urlresolvers import reverse, resolve
def getContent(request, *args, **kwargs):
url = kwargs['url']
try:
v = resolve(url)
except:
data = []
data.append(('some','data'))
return simplejson.dumps(data)
dajaxice_functions.register(getContent)
I ran python manage.py collectstatic, and I get the following output:
Copying '/tmp/tmpm8OlOw'
However, the dajaxice.core.js generated does not have my function getContent at all. Where am I going wrong? I have dajaxice installed properly and everything, I hope.
Seems you forgot to call dajaxice_autodiscover() from urls.py (this is the place recommended by dajaxice author)
this call will load ajax.py module and make it's method discoverable by JS code generator
You need to register you function with dajaxice either using #dajaxice_register decorator or other methods mention in the documentation.
http://django-dajaxice.readthedocs.org/en/latest/quickstart.html#create-your-first-ajax-function