Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use current logged in user as PK for Django DetailView?

When defining URL patterns, I am supposed to use a regular expression to acquire a PK from the URL.

What if I want a URL that has no PK, and if it's not provided, it will use the currently logged in user? Examples:

  • visiting /user will get a DetailView of the currently logged in user
  • /user/edit will show an UpdateView for the currently logged in user

I tried hard-coding the pk= in the Detail.as_view() call but it reports invalid keyword.

How do I specify that in the URL conf?

My sample code that shows PK required error when visiting /user URL:

urlpatterns = patterns('',
    url(r'user/$', 
        DetailView.as_view(
            model=Account,
            template_name='user/detail.html')),
)`
like image 568
radj Avatar asked Mar 05 '13 03:03

radj


2 Answers

An alternative approach would be overriding the get_object method of the DetailView subclass, something along the line of:

class CurrentUserDetailView(UserDetailView):
    def get_object(self):
        return self.request.user

Much cleaner, simpler and more in the spirit of the class-based views than the mixin approach.

EDIT: To clarify, I believe that two different URL patterns (i.e. one with a pk and the other without) should be defined separately in the urlconf. Therefore they could be served by two different views as well, especially as this makes the code cleaner. In this case the urlconf might look something like:

urlpatterns = patterns('',
    url(r"^users/(?P<pk>\d+)/$", UserDetailView.as_view(), name="user_detail"),
    url(r"^users/current/$", CurrentUserDetailView.as_view(), name="current_user_detail"),
    url(r"^users/$", UserListView.as_view(), name="user_list"),
)

And I've updated my example above to note that it inherits the UserDetailView, which makes it even cleaner, and makes it clear what it really is: a special case of the parent view.

like image 143
Berislav Lopac Avatar answered Nov 14 '22 23:11

Berislav Lopac


As far as I know, you can't define that on the URL definition, since you don't have access to that information.

However, what you can do is create your own mixin and use it to build views that behave like you want.

Your mixin would look something like this:

class CurrentUserMixin(object):
    model = Account

    def get_object(self, *args, **kwargs):
        try:
            obj = super(CurrentUserMixin, self).get_object(*args, **kwargs)
        except AttributeError:
            # SingleObjectMixin throws an AttributeError when no pk or slug
            # is present on the url. In those cases, we use the current user
            obj = self.request.user.account

        return obj

and then, make your custom views:

class UserDetailView(CurrentUserMixin, DetailView):
    pass

class UserUpdateView(CurrentUserMixin, UpdateView):
    pass
like image 34
asermax Avatar answered Nov 14 '22 21:11

asermax