How to change settings variable to be different for every user - django

MY views.py
def change_currency(request):
settings.CURRENCY = request.POST['currency']
return HttpResponseRedirect('/')
My settings.py
CURRENCY = 'EUR'
My form
<form action="{% url 'change_currency' %}"
method="POST" class="currency">
EUR
{% csrf_token %}
<input style="display: none" value="EUR" name="currency">
</form>
Problem 1
If I manually change the settings.CURRENCY variable in everything works like a charm, but if I make a form and try to change the settings.CURRENCY it doesn't work
Problem 2
Will it be possible to have a variable in settings.py that change for different users
Problem 3
I can't use sessions, beause i use settings.CURRENCY in filters.py and I don't know how to use request.session in filters.py

First of all you can access request and therefore session in filter.
The solution you try to use does not work for several reasons.
Settings are imported once
When you import module object like this into another module (for example myapp.views):
from settings import CURRENCY
the changes done to settings.CURRENCY will not be visible in the views module. The import happens once and the value at import time is bound to variable in the module.
Multiple workers
Even if you change the variable in views module there is another problem. If you are running non develop server (like gunicorn) it starts several processes to handle requests. It may happen that a change done to settings is processed by one process and the next request is processed by another worker which has the old value.
There should be one place where this settings is stored. Session is a good place as it is global and private to user.

Related

Django: calling view function without url mapping

How do I pass information from an HTML form to my Python code, without having to specify a url mapping? For example, the following code sends data from the form in my 'index.html' template, to the 'myview' mapping, which then calls the 'myview' view function, which finally renders the 'mypage' template...
index.html
<form method="get" action="{% url 'myview' %}">
urls.py
urlpatterns = patterns('',
url(r'^mypage/$', views.myview, name='myview'),
)
views.py
def myview(request):
return render(request, 'myapp/mypage.html')
However, do I really have to have a url mapping for this? What if I do not want to reload another webpage, and I just want to stay in the same 'index.html' page?
I'm just a little confused over how views are actually called, in the case when I want the view to act more like a traditional function, to process some data, rather than to necessarily render a new template.
Thank you!
You always need a URL if you want your browser to call a view. How else would the server know which view to call? The only way is through the URL mapping. Remember that there is no persistent relationship between the browser and the server: the only way they can communicate is through requests to URLs.
You don't always need to render a template, though. A view can return anything, including raw text or JSON.
I don't understand what you mean about not reloading another page. Posting data to the server is a request for another page: that's just how HTTP works. You can certainly choose to post to the same page you're currently on; and in fact that's exactly how forms are processed in the recommended Django pattern. But you still need a URL mapping pointing at that page, in order to get it in the first place as well as to process the submitted dat.
Besides understanding and accepting Daniel Roseman's answer you could also look at these two packages:
Django Rest Franework
jQuery Form Plugin

How to put multiple models on the same page?

I'm doing a website in html and base (where all pages extend) I want
to put a session of social network icons. As this session is base on
html it should be displayed on all pages of the website.
I do not want
to put this session in a static html, I want to do in django using
models. This is already done.
Question: Do I have to put the session of social network icons on each view, or can I make a separate view and all others extend this view?
How can I do this?
Try using an inclusion tag. You can create a function for doing all of the work to create the sessions and then associate that with a particular block of HTML.
templatetags/session.py
#register.inclusion_tag('includes/session_box.html')
def output_session_box(...):
...
return { .. }
The associated template file, includes/session_box.html, would have the HTML like any template.
And then your base.html would have:
{% load session %}
{% output_session_box ... %}
Use RequestContext and a context_processor to inject template variables into every view using RequestContext.
It's as simple as a python function accepting request as an arg, and returning a dictionary to be passed into your template.
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.RequestContext
def my_processor(request):
return {'foo': 'bar'}
TEMPLATE_CONTEXT_PROCESSORS = (
# add path to your context processor here.
)
I generally have a per-project processor for the basics... It's exactly how django adds {{ user }} or {{ STATIC_URL }} to every template.

Find the required permissions of Django URLs without calling them?

My Django app currently has URLs which are protected by 'permission_required()' functions.
This function is called in three different ways.
As a decorator in views.py, with hardcoded parameters.
As a plain function, with autogenerated parameter, in custom Class Based Generic Views.
As a function invoking views in urls.py, with hardcoded parameters.
I'm now adding a menu system to the app, and I need to make menu entries reflect whether the user has permission to request the URL of each menu entry. (Either by greying-out or hiding said entries.)
Is there a way of query the permissions required to a URL without requesting the URL?
The only solution I've thought of so far is to replace the decorator with a parameterless 'menu_permssion_required()' decorator and hardcode all of the permissions into a Python structure. This seems like a step backwards, as my custom Class Based Generic Views already autogenerate their required permissions.
Any suggestions on how to make a menu system which reflects URL permissions for the current user?
Here is an example of how to solve your problem:
First, Create a decorator wrapper to use instead of permission_required:
from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.core.exceptions import PermissionDenied
from functools import wraps
from django.utils.decorators import available_attrs
def require_perms(*perms):
def decorator(view_func):
view_func.permissions = perms
#wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
for perm in perms:
return view_func(request, *args, **kwargs)
raise PermissionDenied()
return _wrapped_view
return decorator
Then, use it to decorate your views:
#require_perms('my_perm',)
def home(request):
.....
Then, add a tag to use for your menu items:
from django.core.urlresolvers import resolve
def check_menu_permissions(menu_path, user):
view = resolve(menu_path)
if hasattr(view.func, "permissions"):
permissions = view.func.permissions
for perm in permissions:
if user.has_perm(perm):
return True # Yep, the user can access this url
else:
return False # Nope, the user cannot access this url
return True # or False - depending on what is the default behavior
And finally, in your templates, when building the menu tree:
<button href="{{ some_path }} {% if not check_menu_permissions some_path request.user %}disabled="disabled"{% endif %} />
N.B. I've not tested the last part with the tag, but I hope you got the idea. The magic thing here is to add the permissions to the view_func in the decorator, and then you can access this using resolve(path). I'm not sure how this will behave in terms of performance, but after all that's just an idea.
EDIT: Just fixed a bug in the example..
Is there a way of query the permissions required to a URL without requesting the URL?
User.has_perm() and User.has_module_perms()
Any suggestions on how to make a menu system which reflects URL permissions for the current user?
I really like this question, because it concerns anyone that makes a website with django, so I find it really relevant. I've been through that myself and even coded a menu "system" in my first django project back in 2008. But since then I tried Pinax, and one of the (so many) things I learnt from their example projects is that it is completely unnecessary bloat.
So, I have no suggestion which I would support on how to make a menu "system" which respects the request user permissions.
I do have a suggestion on how to make a simple menu which respects the request user permissions, so that might not be completely unrelated.
Just make your menu in plain HTML, it's not like it's going to change so often that it has to be generated. That will also keep your Python code simpler.
Add to settings.TEMPLATE_CONTEXT_PROCESSORS: 'django.core.context_processors.PermWrapper'
Use the {{ perms }} proxy to User.has_perms.
Example:
{% if perms.auth %}
<li class="divider"></li>
{% if perms.auth.change_user %}
<li>
{% trans 'Users' %}
</li>
{% endif %}
{% if perms.auth.change_group %}
<li>
{% trans 'User groups' %}
</li>
{% endif %}
{% endif %}
{# etc, etc #}
That's how I keep navigation simple, stupid, and out of the way. But also I always include an autocomplete not far from the menus to allows the user to navigate to any detail page easily. So, that's all I know about navigation in django projects, I'm eager to read other answers !
I had a similar issue, but it went a little deeper. Instead of just permissions, I also wanted other tests based on the lidded in user (ie, is_staff, or user.units.count() > 1). Duplicating these in the view and the template seems prone to errors.
You can introspect a view object, and see all of the decorators wrapping it, and work out if they are checks (in my case: the first argument I'd u or user). If they all pass, then allow rendering the link.
Get all decorators wrapping a function describes the technique in a little more detail. You can find the app that wraps this up into a handy replacement for {% url %} at Django-menus.

Embed an optional Django application in another page, if that app is present

We have a Django project installed at multiple sites. At a couple of them, there will also be an app which produces a status box which should show on the front page, say. What's the right way to have it show up, if the app happens to be installed. If the app is not present, then nothing should display.
I think I could do it by having the status app extend the main index page:
{% extends "mainproject/index.html" %}
{% block statusboxplaceholder %}
<div> status here </div>
{% endblock %}
Is that the right, idiomatic approach? It seems slightly counterintuitive to extend the entire front page just to add a little bit of content.
EDIT: Also, how do I manage the fact that my app will want to define its own "index" page, that should be shown in preference to the project-wide "index" page? I obviously don't want to hard-code a reference to it in the project's urls.py. Do I create a deployment-specific urls.py which refers to specific apps that are installed at that deployment? And if so, isn't that repeating the information in INSTALLED_APPS, and hence violating DRY?
Although I don't see a problem with your approach, but I think a generic template tag would provide the most flexibilty, especially if you want to extend this ability to other applications that you might install later.
Your base template loads a generic "boxes" tag. In the tag's source, you can then render whatever you want based on the installed apps for that particular instance. So you can have a set of default apps to render boxes for, or the end user can customize which apps should have boxes rendered.
In your settings, configuration or even in the tag itself, you can identify the template to render for the block per app.
Assuming that each app has its templates in app/templates directory - this psuedo should get you going (this is untested):
from django.conf import settings
from django import template
register = template.Library()
class GenericBox(template.Node):
def __init__(self, app):
self.app = app
def render(self, context):
if self.app not in settings.INSTALLED_APPS:
return '' # if the app is not installed
# Here you would probably do a lookup against
# django.settings or some other lookup to find out which
# template to load based on the app.
t = template.loader.get_template('some_template.html') # (or load from var)
c = template.RequestContext(context,{'var':'value'}) # optional
return t.render(c)
#register.tag(name='custom_box', takes_context=True, context_class=RequestContext)
def box(parser, token):
parts = token.split_contents()
if len(parts) != 2:
parts[1] = 'default_app' # is the default app that will be rendered.
return GenericBox(parts[1])

How to use 'user.username' in the settings.py

I'm having trouble with my URL forwarding after successful login.
The django default for 'LOGIN_REDIRECT_URL' is '/accounts/profile/'. In my case it should forward to '/user/{{ user.username }}/'
I went to overwrite it in my settings file but have encountered a syntax issue. Here's the code:
LOGIN_REDIRECT_URL = "/user/%s/" % user.username
When I use the following line in my login form, it works, but only if the page is reloaded first. Kinda strange.
<input type="hidden" name="user" value="/user/{{ user.username }}/" />
So what changes must I make to my settings.py to load the username on redirect?
Thanks.
You may want to create a custom login instead and use the views described in django user authentication.
Of course overriding the view where /accounts/profile/ points to and manually setting the redirect url there is an option, but its not a very elegant solution.
Of course there's a syntax issue, you're referencing a variable, user, in settings.py that doesn't exist there. It might help you to go through a Python tutorial to understand Python's scoping rules.
In any case, settings.py is for static global settings. Usernames obviously vary per user, so you can't put a dynamic setting there.