i'm trying to do a basic blog to display what i'm working on.
I was currently making a invisible route to make post directly onto it so i don't need to update my blog everytime i finish a new project, and created a ghost "post" page.
Still, somebody could find the link and i'd like to put some kind of password prompt to validate the post method, is there a way to do that without making a whole login/user system ? (Like using #login_required and all)
Thanks !
You'll want to use Flask BasicAuth. You won't need a database as you will only add one user right where you config the app, like so:
from flask_basicauth import BasicAuth
app = Flask(__name__)
app.config['BASIC_AUTH_USERNAME'] = 'john'
app.config['BASIC_AUTH_PASSWORD'] = 'matrix'
basic_auth = BasicAuth(app)
#app.route('/secret')
#basic_auth.required
def secret_view():
return render_template('secret.html')
Then you would simply add the "#basic_auth.required" decorator to your "post" route. Alternatively, you could simply name the route something that cannot be guessed, like a random string of characters.
more BasicAuth info here
For the past two days I've been trying to intergrate flask-admin to my already existing flask application. But the problem is that I keep getting the same error:
builtins.AssertionError
AssertionError: A name collision occurred between blueprints <flask.blueprints.Blueprint object at 0x000001D8F121B2B0> and <flask.blueprints.Blueprint object at 0x000001D8ECD95A90>. Both share the same name "admin". Blueprints that are created on the fly need unique names.
and that error comes from this block of lines:
Main flask application:
app.route("/admin")
def admin():
if not session.get('logged_in'):
return redirect(url_for('login'))
return adminScreen.adminPage()
admin.py
def adminPage():
admin=Admin(app)
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Role, db.session))
admin.add_view(ModelView(PointOfSale, db.session))
return admin
And what I want to do is to manage the users that I already have in my database by using the functions that flask-admin provide.
So my question is; is there a simple way to route flask-admin to my pre-existing flask application?
P.S I already know that there is this post from May of 2018, but I have no idea how to implement the solution that was provided.
You don't have to create an app.route("/admin") yourself. That is provided by the built-in blueprint from flask-admin.
In order to use blueprints correctly you should update your app to use app factory instead global variable. Otherwise you cannot have multiple instances of the application.
In existing project it may require some work to do but it's worth it.
Example factory may looki like this:
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend
app.register_blueprint(admin)
app.register_blueprint(frontend)
return app
You can find more information here:
http://flask.pocoo.org/docs/1.0/patterns/appfactories/
While trying to link to Flask-Securities register view in my template with:
<li>Register</li>
I get a routing error
werkzeug.routing.BuildError
werkzeug.routing.BuildError: Could not build url for endpoint 'security.register'. Did you mean 'security.login' instead?
From what I've searched around for, setting the Flask Security config line "SECURITY_REGISTERABLE" to True should have fixed it, and yet it's set to True and I'm still getting this error...
I setup Flask Security in my models.py like so:
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
I just had the exact same error after refactoring my app. In my new app.py I missed these config settings:
# More Flask Security settings
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_REGISTER_URL'] = '/admin/create_account'
app.config['SECURITY_LOGIN_URL'] = '/admin/login'
app.config['SECURITY_POST_LOGIN_VIEW'] = '/admin'
app.config['SECURITY_LOGOUT_URL'] = '/admin/logout'
app.config['SECURITY_POST_LOGOUT_VIEW'] = '/admin'
app.config['SECURITY_RESET_URL'] = '/admin/reset'
app.config['SECURITY_CHANGE_URL'] = '/admin/change'
app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = ['email', 'username']
The example above uses url endpoint inside my "Flask Admin" /admin
In your case i'm not exactly sure: by default flask security should be able to find the template folder and routes in the Flask Security package I think. The quickstart docs don't mention any routes that you've you need to manually setup.
You'll also need a app config with something like this:
app.secret_key = 'SECRETSTUFF'
Probably an good idea to add explicit routes for the register page.
The above error is occuring because there is no register() route available in the security blueprint or may be you have named register route as login() in your code. Plz recheck your code. By my little knowledge in flask-Security i think register view is enabled by default. To define the register view you just need to decorate the route using #security.route('/register). I hope this is useful.
I need to localize a django project, but keep one of the applications (the blog) English only.
I wrote this middleware in order to achieve this:
from django.conf import settings
from django.core.urlresolvers import resolve
class DelocalizeMiddleware:
def process_request(self, request):
current_app_name = __name__.split('.')[-2]
match = resolve(request.path)
if match.app_name == current_app_name:
request.LANGUAGE_CODE = settings.LANGUAGE_CODE
Problem is, it assumes the middleware lies directly in the application module (e.g. blog/middleware.py) for retrieving the app name. Other projects might have the middleware in blog/middleware/delocalize.py or something else altogether.
What's the best way to retrieve the name of the currently running app?
You can use Django's resolve function to get the current app name.
https://docs.djangoproject.com/en/dev/topics/http/urls/#resolve
I want to have some constants in a Django Projects. For example, let's say a constant called MIN_TIME_TEST.
I would like to be able to access this constant in two places: from within my Python code, and from within any Templates.
What's the best way to go about doing this?
EDIT:
To clarify, I know about Template Context Processors and about just putting things in settings.py or some other file and just importing.
My question is, how do I combine the two approaches without violating the "Don't Repeat Yourself" rule? Based on the answers so far, here's my approach:
I'd like to create a file called global_constants.py, which will have a list of constants (things like MIN_TIME_TEST = 5). I can import this file into any module to get the constants.
But now, I want to create the context processor which returns all of these constants. How can I go about doing this automatically, without having to list them again in a dictionary, like in John Mee's answer?
Both Luper and Vladimir are correct imho but you'll need both in order to complete your requirements.
Although, the constants don't need to be in the settings.py, you could put them anywhere and import them from that place into your view/model/module code. I sometimes put them into the __init__.py if I don't care to have them to be considered globally relevant.
a context processor like this will ensure that selected variables are globally in the template scope
def settings(request):
"""
Put selected settings variables into the default template context
"""
from django.conf import settings
return {
'DOMAIN': settings.DOMAIN,
'GOOGLEMAPS_API_KEY': settings.GOOGLEMAPS_API_KEY,
}
But this might be overkill if you're new to django; perhaps you're just asking how to put variables into the template scope...?
from django.conf import settings
...
# do stuff with settings.MIN_TIME_TEST as you wish
render_to_response("the_template.html", {
"MIN_TIME_TEST": settings.MIN_TIME_TEST
}, context_instance=RequestContext(request)
To build on other people's answers, here's a simple way you'd implement this:
In your settings file:
GLOBAL_SETTINGS = {
'MIN_TIME_TEST': 'blah',
'RANDOM_GLOBAL_VAR': 'blah',
}
Then, building off of John Mee's context processor:
def settings(request):
"""
Put selected settings variables into the default template context
"""
from django.conf import settings
return settings.GLOBAL_SETTINGS
This will resolve the DRY issue.
Or, if you only plan to use the global settings occasionally and want to call them from within the view:
def view_func(request):
from django.conf import settings
# function code here
ctx = {} #context variables here
ctx.update(settings.GLOBAL_SETTINGS)
# whatever output you want here
Consider putting it into settings.py of your application. Of course, in order to use it in template you will need to make it available to template as any other usual variable.
Use context processors to have your constants available in all templates (settings.py is a nice place to define them as Vladimir said).
Context processors are better suited at handling more dynamic object data--they're defined as a mapping in the documentation and in many of the posts here they're being modified or passed around to views--it doesn't make sense that a template may lose access to global information because, for example, your forgot to use a specialized context processor in the view. The data is global by definition & that couples the view to the template.
A better way is to define a custom template tag. This way:
templates aren't relying on views to have global information passed into them
it's DRY-er: the app defining the global settings can be exported to many projects, eliminating common code across projects
templates decide whether they have access to the global information, not the view functions
In the example below I deal with your problem--loading in this MIN_TIME_TEST variable--and a problem I commonly face, loading in URLs that change when my environment changes.
I have 4 environments--2 dev and 2 production:
Dev: django-web server, url: localhost:8000
Dev: apache web server: url: sandbox.com -> resolves to 127.0.0.1
Prod sandbox server, url: sandbox.domain.com
Prod server: url: domain.com
I do this on all my projects & keep all the urls in a file, global_settings.py so it's accessible from code. I define a custom template tag {% site_url %} that can be (optionally) loaded into any template
I create an app called global_settings, and make sure it's included in my settings.INSTALLED_APPS tuple.
Django compiles templated text into nodes with a render() method that tells how the data should be displayed--I created an object that renders data by returnning values in my global_settings.py based on the name passed in.
It looks like this:
from django import template
import global_settings
class GlobalSettingNode(template.Node):
def __init__(self, settingname):
self.settingname = settingname;
def render(self, context):
if hasattr(global_settings, self.settingname):
return getattr(global_settings, self.settingname)
else:
raise template.TemplateSyntaxError('%s tag does not exist' % self.settingname)
Now, in global_settings.py I register a couple tags: site_url for my example and min_test_time for your example. This way, when {% min_time_test %} is invoked from a template, it'll call get_min_time_test which resolves to load in the value=5. In my example, {% site_url %} will do a name-based lookup so that I can keep all 4 URLs defined at once and choose which environment I'm using. This is more flexible for me than just using Django's built in settings.Debug=True/False flag.
from django import template
from templatenodes import GlobalSettingNode
register = template.Library()
MIN_TIME_TEST = 5
DEV_DJANGO_SITE_URL = 'http://localhost:8000/'
DEV_APACHE_SITE_URL = 'http://sandbox.com/'
PROD_SANDBOX_URL = 'http://sandbox.domain.com/'
PROD_URL = 'http://domain.com/'
CURRENT_ENVIRONMENT = 'DEV_DJANGO_SITE_URL'
def get_site_url(parser, token):
return GlobalSettingNode(CURRENT_ENVIRONMENT)
def get_min_time_test(parser, token):
return GlobalSettingNode('MIN_TIME_TEST')
register.tag('site_url', get_site_url)
register.tag('min_time_test', get_min_time_test)
Note that for this to work, django is expecting global_settings.py to be located in a python packaged called templatetags under your Django app. My Django app here is called global_settings, so my directory structure looks like:
/project-name/global_settings/templatetags/global_settings.py
etc.
Finally the template chooses whether to load in global settings or not, which is beneficial for performance. Add this line to your template to expose all the tags registered in global_settings.py:
{% load global_settings %}
Now, other projects that need MIN_TIME_TEST or these environments exposed can simply install this app =)
In the context processor you can use something like:
import settings
context = {}
for item in dir(settings):
#use some way to exclude __doc__, __name__, etc..
if item[0:2] != '__':
context[item] = getattr(settings, item)
Variant on John Mee's last part, with a little elaboration on the same idea Jordan Reiter discusses.
Suppose you have something in your settings akin to what Jordan suggested -- in other words, something like:
GLOBAL_SETTINGS = {
'SOME_CONST': 'thingy',
'SOME_OTHER_CONST': 'other_thingy',
}
Suppose further you already have a dictionary with some of the variables you'd like to pass your template, perhaps passed as arguments to your view. Let's call it my_dict. Suppose you want the values in my_dict to override those in the settings.GLOBAL_SETTINGS dictionary.
You might do something in your view like:
def my_view(request, *args, **kwargs)
from django.conf import settings
my_dict = some_kind_of_arg_parsing(*args,**kwargs)
tmp = settings.GLOBAL_SETTINGS.copy()
tmp.update(my_dict)
my_dict = tmp
render_to_response('the_template.html', my_dict, context_instance=RequestContext(request))
This lets you have the settings determined globally, available to your templates, and doesn't require you to manually type out each of them.
If you don't have any additional variables to pass the template, nor any need to override, you can just do:
render_to_response('the_template.html', settings.GLOBAL_SETTINGS, context_instance=RequestContext(request))
The main difference between what I'm discussing here & what Jordan has, is that for his, settings.GLOBAL_SETTINGS overrides anything it may have in common w/ your context dictionary, and with mine, my context dictionary overrides settings.GLOBAL_SETTINGS. YMMV.