Django changing custom settings at runtime - python

In my settings.py there are some custom settings, a few data structures that I use. These are rarely changed.
I've noticed that changing them from a view wont work.
How can I force django to reload the settings file at runtime ?
So far the only way that works is to restart the apache web server. But I want to avoid that.

In my code. I needed to kindof reinvent the #login_required decorator for a protected (admin only restricted) page. This is what I did.
In the project/settings.py I created a variable called ACCESS_CP = False
In the app/views.py I imported
from django.conf import settings
In the def login_form
# (if the user is authenticated and the user is an Active Directory Domain Admin)
settings.ACCESS_CP = True
In the def ControlPanel:
if request.method == "GET" and settings.ACCESS_CP == False:
return redirect('login')
elif request.method == "GET" and settings.ACCESS_CP == True:
settings.ACCESS_CP = False
return render(request, 'controlpanel.html')

For your application you can store configuration parameters in redis or django model.
Here is the helpful reusable app for that https://github.com/jezdez/django-constance
Also you can check other existing solutions for django configuration management:
https://www.djangopackages.com/grids/g/configuration/

Import in view.py
import django.conf as conf
def home(request):
conf.settings.SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
conf.settings.DATABASES['default']['NAME'] = 'testdb'

Related

Apply django authentication for all views

I am trying to implement Django basic authentication for all of the views in my views.py file. Although I can add the authentication code snippet in every view, but it will not be easy to apply this to upcoming views. Is there any way that every view in my views.py will automatically check for the authentication?
views.py
def mgmt_home(request):
##############################################################
# This code is repetitive
##############################################################
if request.user.is_anonymous:
return redirect("/login")
##############################################################
test_name = Test.objects.all()[0].test_name
metadata = {
"test_name": test_name,
}
return render(request, "mgmt_home.html", metadata)
Is there any way where I can avoid this repetitive code in all of my views?
you can use 'login_required()' decorator or 'LoginRequiredMixin' class from django authentication.
https://docs.djangoproject.com/en/3.1/topics/auth/default/
How to specify the login_required redirect url in django?
You have 2 options:
from django.contrib.auth.decorators import login_required
You can add this #login_required() decorator to your every view and it will automatically redirect a user to the login page (or whatever page you want to send the user to) any time your user is not logged in.
This option, in your case, I would not recommend, as this might be an overkill and not required for your simple problem. The solution is to create a custom Middleware and add your code to it, and then, of course, add the Middleware to the Settings.py file. This way, each time your views run, your Middlewares will run prior to that. In fact, that's the purpose of Middlewares. They are designed to reduce redundancies and problems exactly such as yours.
Create a middleware.py file anywhere on your python path. Add the below codes to your created middleware.py file
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
def redirect_to_login():
return HttpResponseRedirect(reverse_lazy('users:login'))
class AuthPageProtectionMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
if request.user.is_authenticated:
if not request.user.is_admin:
return redirect_to_login()
else:
return redirect_to_login()
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
NOTE
You can replace the redirection URL with your application-specific one.

Flask - How to properly set global values

I'm currently working on a web app where I'm using Flask and the Flask-User extension to handle authorization. At the moment I have something like this:
#application.route('/dummy')
#roles_required('Admin')
#login_required
def dummy():
in my views.py file and something like this:
{% if current_user.is_authenticated and current_user.has_roles('Admin') %}
in my templates.
Now, there's been a few times where I've changed my mind in terms of role names and then had to search through the whole project to find and replace those usages. I wanted to define something like a ADMIN_ROLE global that can be accessed inside my views.py or any templates. I'd then just change a config file whenever I wanted to change a role's name.
I tried using my config.py setting ADMIN_ROLE = "Admin" and writing #roles_required(current_app.config['ADMIN_ROLE']) but that gives me the following error:
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in a way. To solve
this set up an application context with app.app_context(). See the
documentation for more information.
so that should be wrong. What would be the most correct way to accomplish what I'm trying?
As it says, you can only access config from within the app context. Normally, you do this:
with current_app.app_context():
admin_role = current_app.config['ADMIN_ROLE']
Because you're doing this in a decorator, I don't believe there's anyway to do that. I would suggest just using a separate module. Now, it doesn't appear that you can use python import statements in jinja, so we'll still use app.config for that. Basically we'll create a module with the desired roles and then import that into the config file and your routes file.
roles.py
ADMIN = "Admin"
USER = "User"
config.py
from roles import ADMIN, USER
ADMIN_ROLE = ADMIN
USER_ROLE = USER
routes.py
from roles import ADMIN, USER
#application.route('/dummy')
#roles_required(ADMIN)
#login_required
def dummy():
views.py
{% if current_user.is_authenticated and current_user.has_roles(app.config['ADMIN_ROLE']) %}

Password protect a whole django app

I am running a simple staging env on heroku and I am now looking to password protect the whole app with some sort of simple authentication
I am wondering if there is a simple app or middleware that already supports this.
Have tried looking around for solutions with Heroku / Cloudflare and django, but nothing seems really straight forward.
Django 1.3.1
I use django-lockdown for exactly this purpose. It allows you to add a simple password over the whole of a dev site, without having to add in any extra auth bits on your views that aren't used outside of a dev environment. It also means you can login as admin, or regular users to test whatever your site does
https://github.com/Dunedan/django-lockdown
I use Heroku and Lockdown with this bit of code in my settings.py file
USE_LOCKDOWN = os.environ.get('USE_LOCKDOWN', 'False') == 'True'
if USE_LOCKDOWN:
INSTALLED_APPS += ('lockdown',)
MIDDLEWARE_CLASSES += ('lockdown.middleware.LockdownMiddleware',)
LOCKDOWN_PASSWORDS = (os.environ.get('LOCKDOWN_PASSWORD', 'False'),)
LOCKDOWN_URL_EXCEPTIONS = (r'^/some/url/not/locked/down/$',)
Then obviously set a config var of USE_LOCKDOWN as True on my dev site, and False on my production site so no need to change the code for either.
Django's authentication framework has built-in utilities #login_required which helps you to password protect your view functions (and its corresponding "url" of course).
Usage like this:-
from django.contrib.auth.decorators import permission_required, login_required
#login_required
def view_organization(request, org_slug):
"""
Only permit a logged in user to view the organization.
"""
org = get_object_or_404(organization, slug=org_slug)
org_users = organizationuser.objects.filter(organization=org,\
organization__is_active=true)
template = 'organizations/view_organization.html'
template_vars = {'org_users': org_users, 'org': org}
return render(request, template, template_vars)
For advanced access control, use #permission_required decorator.

Avoiding redundant code in mobile/desktop with Django sites framework

According to the Django docs, the best practice for serving a mobile and desktop application would appear to be the following:
views.py
from django.contrib.sites.models import Site
def my_view(request):
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
# Render desktop home page
elif current_site.domain == 'm.foo.com':
# Render mobile home page
Unfortunately this means that I'll be making the if/then choice in every single view I write. Is it possible for me to instead do the following:
views.py
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
def my_view(request):
# Render desktop home page
elif current_site.domain == 'm.foo.com':
def my_view(request):
# Render mobile home page
I'd like to get some sense of the possibility here before I start tearing through my views.py in an attempt to test this the hard way.
Have you looked at this app: http://pypi.python.org/pypi/django-mobility?
Using a middleware for detecting the device and decorators to switch templates depending on the incoming device are a good approach to avoid redundant if/else constructs.
And if you look at the examples given for django-mobility they look pretty similiar to your desired construct:
def view(request):
...
#mobilized(view)
def view(request):
...
You can use middleware to detect whether or not the request is to the 'm' subdomain or not, and then specify the correct URL conf to direct you to the views you want. I've been using a modified version of the django-subdomains app for this and it's been working nicely. This is an effective and simple solution if your view logic for your mobile site is quite different from the view logic of your regular site. Here's the link:
https://github.com/tkaemming/django-subdomains
Then all you have to do is write a new URL conf for your mobile site, specify this in your settings, and then write your views/templates for your mobile site just like you would for your regular app.

templatetags don't refresh

I have two templatetags in my app which contain forms which show entries in db. When I alter data or add new entry to db, the forms show the old data. While in admin panel everything is correct (updated). When I restart the server (I mean manage.py runserver) forms show updated db entries. How to make the forms show updated data?
regards
chriss
EDIT:
file: templatetags/oceny_tags.py:
from django import template
from oceny.formularze import StudentFormularz, PrzeniesStudentaFormularz
def dodajStudenta(req):
formularz = StudentFormularz(req)
return {'formularz': formularz}
def przeniesStudenta(req):
formularz = PrzeniesStudentaFormularz(req)
return {'formularz': formularz}
register = template.Library()
register.inclusion_tag('oceny/formularz_studenta.html', takes_context = False)(dodajStudenta)
register.inclusion_tag('oceny/formularz_przenies_studenta.html', takes_context = False)(przeniesStudenta)
file: views.py view responsible for handling forms:
def zarzadzajStudentami(request):
formularze = ['dodaj_studenta', 'przenies_studenta']
req = {}
for e in formularze:
req[e] = None
if request.POST:
req[request.POST['formularz']] = request.POST
if request.POST['formularz'] == 'dodaj_studenta':
formularz = StudentFormularz(request.POST)
if formularz.is_valid():
formularz.save()
return HttpResponseRedirect(reverse('zarzadzaj_studentami'))
elif request.POST['formularz'] == 'przenies_studenta':
formularz = PrzeniesStudentaFormularz(request.POST)
if formularz.is_valid():
student = Student.objects.get(id = request.POST['student'])
grupa = Grupa.objects.get(id = request.POST['grupa'])
student.grupa = grupa
student.save()
return HttpResponseRedirect(reverse('zarzadzaj_studentami'))
return render_to_response('oceny/zarzadzaj_studentami.html', {'req': req}, context_instance = RequestContext(request))
I realize that the code may be lame in some cases. I would appreciate any other hints how to write things better.
I have too low rep to comment, but takes_context defaults to False, making your assignment redundant. Also, but now I am guessing, but it might be related to your problem.
Look for "CACHE_BACKEND= ????" in your settings.py file. The value will change as a function of which caching mechanism you are using. Comment this out and restart the server. If your values are now showing correctly, then it was a caching problem.
Are you using some kind of cache system? It could be that.

Categories