Django app to "switch on" other apps for specyfic user - django

I am new to django and I really like its modular construction so I decided to take advantage of it and put all the separated functionalities each in different app.
Now I need a way to switch on and off this apps by both user and admin.
The user options panel would look like this:
[ ] blog
---------------------
[ ] tagging [BUY]
After checking "blog" option user would get the blog in his profile and after buying and checking "tagging" he would get tagging for the blog.
The admin panel would have an ability to show or hide an app from user panel.
I wonder if:
there is an app which would help me switch on and off an app for specyfic user
and if not -
what would be a proper "architecture" for such django app?
Can it be done dynamically in middleware or should it be done during login (check available apps from database, switch them on, redirect to user home page)?
Any advices for such a task?
Thanks,
Robert

I haven't heard of any such app… But I don't expect it would be too hard to build.
If I were doing it, I would put a permissions check in the entry points to each app. For example:
check_app_permission = lambda request: permissions.check_app_permission("blog", request)
def view_blog(request, …):
check_app_permission(request)
…
(it might even be possible to do some magic and inject this check at the urls.py level…)
Additionally, I would create a has_app_permission template tag:
<div id="sidebar">
{% if has_app_permission "blog" %}
{% include "blog/sidebar_recent_posts.html" %}
{% endif %}
</div>
Or similar.
Finally, there are approximately a million ways you could implement the permission system… And without more information I wouldn't be able to comment. The simplest, though, would be something like this:
class App(Model):
name = CharField(…)
class AppPermission(object):
app = ForeignKey(App)
user = ForiegnKey(User)
def user_has_permission(user, app_name):
return AppPermission.objects.filter(app__name=app_name, user=user).exists()
I would avoid trying to do this with middleware, because if I understand the problem correctly, I expect you will (or, at least, I expect I would) end up spending a bunch of time building a generic framework which, in the end, would just have checks similar to those above.
Does that help? Is there something I can clarify?

Related

Django views/templates: list filtering based on a current a site category

In my app user can create and manage organizations -> projects -> resources and so on. A project instance has a FK to organization, resource has a FK to project.
In example, when user selects an active organization, i want projects view to display only projects that belong to this organization. I see these ways:
Optional argument in all specific urls:
url(r'^(?:organization/(?P<organization_id>\d+)/)?projects/$', 'app.views.projects', name='projects'),
url(r'^(?:organization/(?P<organization_id>\d+)/)?(?:project/(?P<project_id>\d+)/)?resources/$', 'app.views.resources', name='resources'),
Also, this method forces to rewrite all {% url %} tags in templates:
`{% url 'projects' org.id %}`
`{% url 'resources' org.id prj.id %}`
but that's all does not look pretty, especially urls.py.
UPDATE 1
This method forces to pass organization_id in templates everytime. Even if I write middleware to avoid annoying passing it in context,
class FetchFiltersMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
request.project_id = view_kwargs.get('project_id', 0)
request.organization_id = view_kwargs.get('organization_id', 0)
anyway, ALL site urls must be rewritten to contain organization_id, otherwise filtering will be broken. Even if it's not necessary, i.e. in user profile view all sidebar links to projects will be broken.
Storing a current filter in cookie or GET argument
like {% url 'myurl' %}&project={{ project_id }}. bad. ugly.
Storing a last selected organization/project id in cache or session
Easy to use. But not userside-explicit. Also it will generate problems when site opened in multiple tabs with different organizations selected on each tab.
At this moment i see first way looks better, but a lot of rewrite work is required. Is there a better way to do category/section based filtering?
UPDATE 2
If it's not clean yet. The selection of the project, or organization - it's actually switching the current display context. In the context of the selected organization all links should lead to projects in this organization, and so on.
I personally prefer the first way. If you have a relatively simple structure, you can simplify your template by using get_absolute_url. For example, {{ org.get_absolute_url }} could lead to the projects view, {{ prj.get_absolute_url }} to resources etc.
In an older project, I used the session-way, and still regret it, exactly because of the problems with multiple tabs/windows. Using a cookie has the same problems. I think the "ugliness" of the URL configuration in the first way is worth the gain in usability.

Django/Haystack - best option to have a listview with search capability

I have an app with a Restaurant model. I'd like to understand what is the best way to put together a view that displays the list of restaurant objects, but also has a search form above that a user could enter parameters to filter the results displayed. If no parameters are entered, all the restaurants should be shown. I'm already using haystack and have a search form, but currently it is on a standalone search.html template. I also have an ListView on a separate template, and I guess I'm looking for an end result that combines these.
I did some reading on line and it's unclear what the best way to do it is:
using just listview from Django with some queryset filtering
combining haystack SearchView with django class based views?
this is my best bet so far - creating a customized version of SearchView from Haystack
ideally, ultimately the search capabilities would include things like allow autocompleting the user's inputs, and dynamically filter the results as the user types.
any thoughts on what the best way is to go about this and any examples out there?
There probably is out there some package that gives you everything automatically, displaying the queryset list and allowing simple adding of a search bar and so on (like the admin site). But I take it you are still a beginner to web development, so I'd strongly suggest you drop the listviews, drop haystack, drop everything, and do it all yourself.
See, they're not bad approaches or anything, but they're like shortcuts. And shortcuts are good only if they shorten the original way, which in your case isn't all that long.
To give you an example, here's a simple approach to displaying a list of items:
views.py
def restaraunt_list(request):
restaraunts = Restaraunt.objects.all().order_by('name')[:100] # Just for example purposes. You can order them how you'd like, and you probably want to add pagination instead of limiting the view number arbitrarily
context = {'restaraunts': restaraunts}
return render_to_response('index.html', context)
index.html:
<ul>
{% for rest in restaraunts %}
<li>{{ rest }}</li>
{% endfor %}
</ul>
That's it. Now it displays it in a list. Now to add a search filter all you need to do is this:
index.html (add this anywhere you want it)
<form>
<input type='text' name='q' id='q'></input>
<input type='submit' value='search!'></input>
</form>
When a user sends the data from 'q' it is sent through GET, and then on server side you add this:
def restaraunt_list(request):
restaraunts = Restaraunt.objects.all()
# filter results!
if request.method == 'GET':
q = request.GET['q']
if q != '':
restaraunts = restaraunts.filter(name__contains=q)
# ordering is the last thing you do
restaraunts = restaraunts.order_by('name')[:100]
context = {'restaraunts': restaraunts}
return render_to_response('index.html', context)
Now, this will work, but from what you wrote I understand you want the search to be live the moment a key is pressed. For that, you'd need to use AJAX (go learn how it works, I'm not gonna delve into it here). As for autocomplete, you should check out jQuery UI.
But, like I said, before jumping ahead and using all those stuff, I suggest you first learn the basics. Go through the django tutorial (if you haven't already), and use the amazingly detailed django-docs every step of the way. When some specific things won't work and you're stuck, come here to Stackoverflow and someone will surely help you. good luck!

How to display a post registration welcome message when using both django-registration and django-socialauth?

This is a pretty trivial question but I must be missing something because I can't come up with a solution I'm happy with.
I'm using two libraries to handle registration, django-registration for the email based registration and django-socialauth for the social based registration, and want to display a welcome message when the user registers for the first time.
My current approach is to have a context processor that checks if the user has registered within the past 2 minutes and if so, updates the request object. This seems inefficient since I'm checking every time when it's only used once.
I tried implementing it using signals but the issue I ran into was that I needed some way to hook into the request but only django-registration passes the request along.
An option I'm contemplating is using the signals to update a record in the database but that seems like overkill for something this simple. Am I missing something obvious?
context_processors.py:
def just_registered(request):
just_registered = False
if request.user.is_authenticated() and request.user.email:
if request.user.date_joined < datetime.today() + timedelta(minutes=2):
if 'just_registered' not in request.session:
just_registered = True
request.session['just_registered'] = just_registered
return { 'just_registered' : just_registered }
you can use django messages and implement it in your template
{% if messages %}
{% for message in messages %}
{{message}}
{% endfor %}
{% endif %}
.
def just_registered(request):
if request.user.is_authenticated():
if request.user.date_joined < datetime.today() + timedelta(minutes=2):
messages.info(request, "Welcome")
return ''
user is authenticated is already understood, you don't have to put user email because when you register, the email is required
Just to be clear, you want to display a welcome message when the user successfully logs in for the first time (it says register for the first time in your question)? Do they follow an activation link from an email? You could have that emailed link go to a new user version of your landing page.
Otherwise, if you want to use the same page for normal users and people logging in the for the first time, I don't see how you can avoid checking if this is the user's first time logging in. To do that, it seems like using a boolean attrib on the user (or fk'ed to them) that keeps track of whether they have logged in before would be the way to go, instead of looking at how long ago they activated the account (what if they activated 2 days ago but didn't log in?)
Following from your comment on princesses answer your best bet would be to save some kind of data when the user logs in for the first time.
I would suggest write a simple middleware which detects first login and saves that in a persistent form
Have a look at this:
http://blog.elcodo.pl/post/926902087/django-detect-users-first-login
You can also checkout the middleware in django tracking
https://github.com/codekoala/django-tracking/blob/master/tracking/middleware.py
It is slightly inefficient , however I don't see any other way given the statelessness of HTTP

Django - Pre render signal?

I have a 'live settings' app which I use to store certain global site settings. Certain pages of my site reference these settings, although generally they only use 2-3 at a time. I access these settings using a custom template tag like so:
{% settings site_name %}
Each time I use this tag, the model will retrieve the setting from the database, so if I had something like:
{% settings site_name %} {% settings num_articles %}
the database would get queried twice.
What I'd like to do is not hit the database more than once per page for the settings values, if I could get all the settings used on a page and then hit the database to retrieve them all, that would be much better.
I had a look through the documentation and it seems Django has no pre render signal which I could use to update any references to the settings, so does anyone have any suggestions how I could optimise this system? And yes obviously caching is the obvious answer but I'd still like to improve on this for when the page isn't cached.
Agreeing with Daniel that process_template_response is the hook you're looking for. I don't know how many settings you have, but it could also make sense to retrieve all settings once, and store them in some dictionary like structure, so you can access them anytime without hitting the database. You could retrieve them once either per request, or - even if your settings do barely change - when django initializes. You could additionally use django's signals to update your cached settings on delete or update.
If you have a look at django-dbsettings you will see it does a similar thing!
Django 1.3 includes the new TemplateResponse class, which allows you to modify the response later in the rendering process - eg in middleware. This looks like it might do what you want.
If you wish to stick to a scheme similar to what you already have, I'd implement a filter that takes in a list of keys and returns a dict with all the relevant values.
Example filter:
def get_settings(key_list):
# take values from conf.settings. In practice, can be from any source
return dict((k, getattr(settings, k, None)) for k in key_list.split(","))
register.filter("get_settings", get_settings)
Usage:
{# load multiple values with a single call #}
{% with "KEY1,KEY2"|get_settings as settings %}
setting values {{ settings.KEY1 }} and {{ settings.KEY2 }}
{% endwith %}
Note that I used a filter instead of a tag because the with builtin expects a single value before as.

Flickr albums in django admin

I want to do the following:
Having a model (p.e. a model which handles data about photographic reports) create a section which has a preview of an specific flickr album. The URL will be provided by an URLField (until the first save the preview will not be available).
After the first save, it'll show previews of all the images inside that album, and make them selectable (through jQuery for example). Then again, when the images are selected and the object is saved (I think I can use django signals for this) it will notify a specific user telling him a selection has been made.
Is there any plugins available, or any easy way to implement this in django-admin?
Update: 22 days and no anwers... does that mean it can't be done in django-admin?
I personally can't think of any easy way to implement this in the Django admin, simply because I doubt many people who've done it have thought to open source it. I can imagine that it would be very specific to a certain user's / programmer's needs.
In any case, if you wanted to solve this issue, I'd say that your best bet would be overriding the Django admin templates in your django/contrib/admin/templates/admin folder. I believe you'd be best off by editing change_form.html.
My basic approach would be this:
Check the name of the model using opts.verbose_name. For example, if you wanted to do this processing for a model whose verbose name is "Gallery", you would do
{% ifequal opts.verbose_name "Gallery" %}
<!-- neat gallery view -->
{% else %}
<!-- regular form -->
{% endifequal %}
Make a custom template tag that will display the gallery view / form given the object_id and the type of object. This way you can replace the <!-- neat gallery view --> with a {% show_gallery object_id %}. See the Django Docs for more info on creating custom template tags. It's pretty straightforward.
Add whatever Javascript or custom stuff in your template tag template. What you choose to do is up to you.
Sorry you haven't gotten many more answers to your question. Hope this helps!