2

I'm adding a new type of user profile to site and this new type of user(say new_type) should not be able to reach the same views like the existings users.

My question is: how can i use different types of views according to user type using the same request paths without altering the existing view codes like adding

if user.profile_type == 'blah':
    do_this 
else: 
    do_that 

to each view?

In detail:

i'd like to use "http://mysite.com/path/" for both types of users, running different logics and returning different displays without making differences in existing views (since there are lots of views to modify).

I'm thinking of adding different groups of views for new type, then override urls logic to resolve the request paths to relevant views, such as :

if user is of new_type 
    resolve path to related_view_for_new_type
else
    resolve as usual 

As a straight forward example: logging in admin and normal user from the same login url, and if user is admin, run the relevant views for admin and return django admin display to her, if normal user, then run the normal view and return normal website view to her, without rewriting or changing the url they are requesting. (/index/ for example)

Is it possible to extend urls in Django in such way and if so how, or should i give up overloading the same request paths and add '/new_type/' to urls (http://mysite.com/new_type/path/)for new_type users?

Thanks

altunyurt
  • 2,821
  • 3
  • 38
  • 53

3 Answers3

2

To start with, what does it mean to have different types of users? A very simple way to do this would be to store an attribute on a user. That way, given a user object, you could look at this extra attribute to determine whether the user is of a special type. Django has a standard mechanism for storing additional attributes like this, which you can read about here.

Once you have a way of determining user types, you can create a single decorator and apply it to any view that needs to behave in the way you've described. Decorators are a great way of applying extra conditions or behaviour to existing functions. The logic in the decorator gets to work before and/or after the existing function, so it can very easily accomplish something like displaying a different template based on a the user's type.

Decorator functions look very odd when you first encounter them, but read it carefully and you'll soon get it. The decorator is a function itself, and you give it the function you want to decorate. It gives you back a new function, which is your old function wrapped with the extra logic.

I've written some untested example code below.

def template_based_on_user_type(special_template, ordinary_template):
    def decorator(your_view_function):
        def inner_decorator(request, *args, **kwargs):
            # this is the logic that checks the user type before 
            # every invocation of this view:
            if request.user.type == 'special_type':
                template = special_template
            else:
                template = ordinary_template

            # this is the invocation of the view function, with
            # a custom template selected:
            return your_view_function(request, template)
        return inner_decorator
    return decorator

@template_based_on_user_type('my-special-template.html', 'ordinary-template.html')
def my_view_function(request, template='default.html'):
    # Do what you need to do here
    render_to_response(template, data, RequestContext(request)

The syntax for applying a decorator is the "@" symbole, followed by the decorator function. The decorator is customized with the template names specified.

Gareth
  • 1,430
  • 11
  • 15
  • thanks for the detailed answer. it seems my question is somewhat ambiguous. I want both user types to be able to reach mysite.com/path/ but see different results of different logics where logics need not have any similarities. i'm updating the question with some more details. – altunyurt Jul 09 '11 at 12:17
  • I assumed you had one existing view function and you wanted to display different content without writing another view function. – Gareth Jul 09 '11 at 13:18
0

I solved this problem using decorator in urls.py:

def dispatch_by_user(staff_view, external_user_view):
    def get_view(request, **kwargs):
        if (is_staff_user(request.user)):
            return staff_view(request, **kwargs)
        else:
            return external_user_view(request, **kwargs)
    return login_required(get_view)

def is_staff_user(user):
    return user.groups.filter(name="privileged-group").exists()

So patterns set as following:

urlpatterns = [
    url(r'^$',
        dispatch_by_user(
                views.StaffHomeView.as_view(),  
                views.ExternalUserClientView.as_view()),
        name='index'),
     # ...
]
fresheed
  • 103
  • 1
  • 7
-1

RTFM as usual :)

Here's the link to a possible solution : method_splitter @ http://www.djangobook.com/en/2.0/chapter08/

new_type related views' names will be derived from the originals by adding new_type_ to beginning of the name, such as index-> new_type_index

then i'll determine the view to return by simply checking the request.user.is_new_type attribute. ugly, but better than modifying gazillions of views.

altunyurt
  • 2,821
  • 3
  • 38
  • 53