3

I have a basic permission system where I am pretty much hardcoding permissions based on user.profile.user_type, where user.profile is equivalent to user.get_profile().

For example, if a user_type is, say, 1 (property manager), then that user can view all work orders. A user_type of 2 (tenant) means that user can only view work orders that he created.

I am currently simply using a class-based generic view in urls.py like this

url(
    r'^orders/$',
    ListView.as_view(
        model = Order,
        template_name = 'doors/orders/list.html'
    ),
    name = 'orders_list'
),

and therefore I have no permissions control at all.

So to add a permissions system, should I control it in the template like this?

{% for order in order_list %}
    {% if request.user.profile.user_type == 1 %}
        # Show every order
        {{ order.pk }}
    {% else %}
        # Show only work orders created by that user
        {% if order.creator == request.user.pk %}
            {{ order.pk }}
        {% endif %}
    {% endif %}
{% endfor %}

I have a feeling that trying to filter inside the template is a waste of a lot of SQL hits, because no matter what the user_type is, the template will still force Django to call every work order. Is that true?

Or should I control it in the view like this?

def orders_list( request ) :
    if request.user.user_type == 1 :
        order_list = Order.objects.all()
    else :
        order_list = Order.objects.filter( creator = request.user.pk )

    dictionary = {
        'order_list' : order_list,
    }

    return render( request, 'doors/orders/list.html', dictionary )

Obviously if I try to control it inside views.py, then I can't use the generic views anymore.

And lastly my third option would be to (somehow) control it inside the class-base generic view. I don't even know if that's even possible. Maybe somehow with get_context_data? I really like the simplicity of generic views, but I'm not too familiar with the more advanced OO concepts.

What are you guys's suggestions?

hobbes3
  • 28,078
  • 24
  • 87
  • 116

1 Answers1

2

If you use ListView there is get_queryset() method to do this:

class OrderListView(ListView):
    template_name = 'doors/orders/list.html'

    def get_queryset(self):
        user = self.request.user
        if user.user_type == 1:
            return Order.objects.all()
        return Order.objects.filter(creator=user.pk)
San4ez
  • 8,091
  • 4
  • 41
  • 62
  • Thanks for the response! One quick question: if I wanted to get the total `Order` count regardless of permissions (kind of like Stack Overflow's statistic: 2,904,397 total questions), do I *have* to send it as an [extra context](https://docs.djangoproject.com/en/1.4/topics/class-based-views/#adding-extra-context)? It seems like a lot of code just to send one extra variable to the template. – hobbes3 Apr 08 '12 at 20:07
  • 1
    Yes, you have to do this. Most people consider this to be a disadvantage of CBV, because you need to write quite a lot of rubbish code. But on the other hand, CBV allows you to split your class on levels (queryset, context_data, dispatch, etc) what is more readable and you can use them as Mixins in other View classes – San4ez Apr 08 '12 at 20:29
  • Is there any particular reasons why you used `get_queryset` as oppose to simply defining `queryset = ...`? Is it because there is no way to get the `request.user` information without going inside the `get_queryset` function? I would just define `queryset = ...`, but I'm not sure how to get the user info. – hobbes3 Apr 09 '12 at 08:08
  • 1
    `queryset =` is just a parameter that depends on nothing, like `model` or `template_name`. In `get_queryset` function you can pass `self` as parameter and specify other logic – San4ez Apr 09 '12 at 08:53