Avoiding redundant code in mobile/desktop with Django sites framework - python

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.

Related

Where to best execute database operations using Django framework?

Thanks in advance for any help. I am new to django specifically as well as web development in general. I have been trying to teach myself and develop a website using the Django framework and while everything is working so far, I am not sure if I am really doing things in the best possible way.
Typically, within my django app, I will have certain points where I want to modify the contents of my database model in some way. A typical use case is where I have button on my site that says "Add a post":
models.py:
from django.db import models
# data model import
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
post = models.CharField(max_length=1024)
urls.py:
from django.urls import include, path
from . import views
urlpatterns = [
path('', views.post, name='new_post'),
path('post_exec', views.post_exec, name='post_exec'),
]
views.py:
from django.contrib import messages
from django.shortcuts import render, redirect
# import data models
from django.contrib.auth.models import User
from .models import Post
def post(request):
# make sure the user has privileges
user = User.objects.get(id = request.user.id)
if not user.is_superuser:
return redirect('home')
return render(request, 'post.html')
def post_exec(request):
# make sure the user has priveledges
user = User.objects.get(id = request.user.id)
if not user.is_superuser:
return redirect('home')
# create the post
new_post = Post.objects.create()
new_post.user = user
new_post.post = request.POST['post']
new_post.save()
# this could redirect to a confirmation page or something too
return redirect('home')
You can see what I am doing here is that everytime I need a change to the database due to user input, I am executing the code to do the requested database change in a django view and then redirecting to another page following completion of the database change. While this works, it feels kind of clunky (you end up needing pages that you never actually use), it seems pretty sketchy in terms of security (although I am checking for credentials on each page), and I imagine there is a better way to do this.
Can any experience Django developers offer some advice for how I should be best structuring my project for these specific types of common database operations?
The Django's views is a good place to organize the project's CRUD system so users can manage their data. You can use the class-based views to group the GET, POST etc requests. Also there are better ways of using the authorization system with the login_required() decorator, the LoginRequiredMixin class and other solutions that you can rich here

Django changing custom settings at runtime

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'

how to run multiple websites and serve different content in django 1.6?

I want to start one project of django and ideally it will have one admin panel .
I want to point different domains and subdomains (subdomains on more priority) and want to serve different content and pages when some1 hit my server .
So to be in details if i have two domains :
1) abc.com
2) xyz.com
Then if someone put abc.com then i should be able to see page1 and all urls associated with this abc.com should be available and should be able to see page2 when someone use xyz.com
and xyz.com/new/ should deliver different content and abc.com/new/ should give different content .
I will suggest you to use Mezzanine for this . It is very strong CMS framework build into django.
To implement multisite application you can use djagno multisite app . It is very easy to integrate .
With the site framework linked into your models, you can associate data to different sites.
You can also use it in your views like in the example taken from the official doc:
from django.contrib.sites.shortcuts import get_current_site
def my_view(request):
current_site = get_current_site(request)
if current_site.domain == 'foo.com':
# Do something
pass
else:
# Do something else.
pass

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.

using query string in Python Pyramid route configuration

this is very specific to what I am trying to do so I start describing what it is:
a Pyramid app serving plots like http://localhost:6543/path/to/myplot/plot001.png
if the plot is not available another image is served (work.png)
another part is the deform view which provides a HTML form to enter the configuration for a plot like: http://localhost:6543/path/to/myplot/plot001.png?action=edit. Note here the query string "action=edit".
the configuration consists of datafile, templates etc.
the form has save (to save the config) and render buttons (http://localhost:6543/path/to/myplot/plot001.png?action=render). Rendering results into a png file which then is used in a static way.
I figured out all the pieces like rendering using Matplotlib etc. but I am new to Pyramid and Deform. I also have a working view that serves the plot from file. The deform form kind of works, too. At the moment it is unclear to me how to best structure the ULRs to distinguish the serve, edit and render usecases. I guess in Pyramid talk this means how to configure the routes for serve_view and edit_view.
__init__.py:
config.add_route('serve_route',
'/{project_name}/testruns/{testrun_name}/plots/{plot_name}.png')
config.add_route('edit_route',
'/{project_name}/testruns/{testrun_name}/plots/{plot_name}.png')
# can I use query strings like "?action=edit" here to distinguish the difference?
views.py:
#view_config(context=Root, route_name='serve_route')
def plot_view(context, request):
...
#view_config(context=Root, renderer='bunseki:templates/form.pt', route_name='edit_route')
def edit_view(request):
...
I the Pyramid manual I could not find reference how to set parameters in the route. I guess a pointer to some documentation or sample would be sufficient and I can figure out the details myself. Thank you!
There are two ways to do this depending on what you prefer for separating your code.
Put all of the logic into your view, separated by 'if' statements on request.GET.get('action').
config.add_route('plot', '/{project_name}/testruns/{testrun_name}/plots/{plot_name}.png')
config.scan()
#view_config(route_name='plot')
def plot_view(request):
action = request.GET('action')
if action == 'edit':
# do something
return render_to_response('bunseki:templates/form.pt', {}, request)
# return the png
Register multiple views and delegate between them using Pyramid's view lookup mechanics.
config.add_route('plot', '/{project_name}/testruns/{testrun_name}/plots/{plot_name}.png')
config.scan()
#view_config(route_name='plot')
def plot_image_view(request):
# return the plot image
#view_config(route_name='plot', request_param='action=edit',
renderer='bunseki:templates/form.pt')
def edit_plot_view(request):
# edit the plot
return {}
# etc..
Hope this helps. It's an excellent example of registering a single url pattern, and using different views for different types of requests on that url.
I'm not sure you can use contex=Root in that situation, but what you are asking for is probably the matchdict.
__init__.py:
config.add_route('serve_route',
'/{project_name}/testruns/{testrun_name}/plots/{plot_name}.png')
views.py:
#view_config(route_name='serve_route')
def plot_view(request):
project_name = request.matchdict['project_name']
action = request.params.get('action', None)
http://docs.pylonsproject.org/projects/pyramid/1.1/narr/urldispatch.html#matchdict
Edit:
If your question is more a general question regarding routing, you should create one route per action to keep the code of your view functions shorter and clearer. For example, if you want to edit and render, your routes could look something like this:
__init__.py:
config.add_route('render_plot',
'/{project_name}/testruns/{testrun_name}/plots/{plot_name}.png')
config.add_route('edit_plot',
'/{project_name}/testruns/{testrun_name}/plots/{plot_name}/edit')
views.py:
#view_config('render_plot')
def render(request):
pass
#view_config('edit_plot', renderer='bunseki:templates/form.pt')
def edit(request):
pass
A more effective way will be to specify the action in the url. And you can even serve different actions on the same route name or multiple.
config.add_route('serve_route', '/{project_name}/testruns/{testrun_name}/plots/{action}/{plot_name}.png')
views.py
#view_config(context=Root, route_name='serve_route', action='view')
def plot_view(request):
pass
Or with query string
`config.add_route('serve_route',
'/{project_name}/testruns/{testrun_name}/plots/{plot_name}.png')
views.py
#view_config(context=Root, route_name='serve_route')
def plot_view(request):
try:
action = getattr(self._request.GET, 'action')
except AttributeError:
raise

Categories