Global access to request.user

345 views
Skip to first unread message

guettli

unread,
Mar 26, 2015, 6:38:23 AM3/26/15
to django...@googlegroups.com
I have a large legacy application which passes around the request to nearly every method.

Reading this source is no fun.

In about 95% of all cases "request" is not used, but "request.user" is needed for
permission checking.

Example: there is a drop down box with the list of possible actions the user can perform now.
The list of actions is filtered according to the logged in request.user.

I want to get rid of the ugly passing around "request" from method to method.

I have some ideas in mind, but won't post them today. I am afraid that if I would,
the discussion would be only pro/contra my solution. But I guess there is
a third way :-)


Anderson Resende

unread,
Mar 26, 2015, 10:52:07 AM3/26/15
to django...@googlegroups.com
You can use middlewares!!! It is a way...


Esau Rodriguez

unread,
Mar 26, 2015, 12:20:06 PM3/26/15
to django...@googlegroups.com
I don't see how middleware could be used to avoid passing the user or
request parameter to the inner methods.

As this is part of the view, I'd probably write a custom filter or tag, I dunno.

Regards,
Esau.

On Thu, Mar 26, 2015 at 2:52 PM, Anderson Resende
<anderson...@gmail.com> wrote:
> You can use middlewares!!! It is a way...
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users...@googlegroups.com.
> To post to this group, send email to django...@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/2c55f576-7012-49a2-bd53-a8e5fdc4754a%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.



--
Esaú Rodríguez
esa...@gmail.com

aRkadeFR

unread,
Mar 27, 2015, 4:53:35 AM3/27/15
to django...@googlegroups.com
I agree with Anderson, this is one solution, even
though I don't know if it's a good way.

For example a middleware is used to add the user to
the request. You could do the same with the request
to a singleton instance and get it back then from your
form, view etc.? But be aware that some function should
work within the request cycle or without.

A filter or tag is only a way to process/render data inside
the templates. I don't see it as a solution.

guettli

unread,
Mar 27, 2015, 5:18:33 AM3/27/15
to django...@googlegroups.com


Am Donnerstag, 26. März 2015 15:52:07 UTC+1 schrieb Anderson Resende:
You can use middlewares!!! It is a way...



I don't understand how middleware can help here.

The only way I see is that the middleware updates a global variable for the data. In my case request.user.

Anderson, is this what you meant?

This would work. But a lot of people say that you should not use global variables ....

Regards,
  Thomas Güttler

Daniel França

unread,
Mar 27, 2015, 6:06:03 AM3/27/15
to django...@googlegroups.com
I don't understand how middlware or filter would help on those cases.
Why not only pass the variable where it's needed?
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.

Anderson Resende

unread,
Mar 27, 2015, 9:53:31 AM3/27/15
to django...@googlegroups.com

Maybe a global state? Yes!

https://docs.djangoproject.com/en/1.7/topics/http/middleware/#init

I never did that, but you can try!



Anderson Resende

unread,
Mar 27, 2015, 9:58:01 AM3/27/15
to django...@googlegroups.com
Other way is use sessions!
Django provide session midleware.
You can get the session dict out of the view!


Sorry my english, I am a Brazilian guy!


Cal Leeming

unread,
Mar 27, 2015, 10:50:02 AM3/27/15
to django...@googlegroups.com
There is a reason that state is passed around from method to method,
rather than being stored as a global, because this is the correct way
to do things.

However, it sounds like the architectural design of your code is
flawed, as throwing around the request object indicates that you don't
have modularity. If you only need the user object, then why not
replace all instances of "request=request" with "user=request.user".
The alternative is to have some magic threadlocals which stores the
current user, but this is a particularly disgusting way of writing
code and I could not recommend it at all.

It would be better if you could explain a little more about how/where
this request object is being passed around, then we'd be in a better
position to give you the correct advice.

Cal
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users...@googlegroups.com.
> To post to this group, send email to django...@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/fc2c1d65-fa3d-461b-9846-3802cf153e15%40googlegroups.com.

Thomas Güttler

unread,
Mar 27, 2015, 11:31:05 AM3/27/15
to django...@googlegroups.com


Am 27.03.2015 um 15:49 schrieb Cal Leeming:
> There is a reason that state is passed around from method to method,
> rather than being stored as a global, because this is the correct way
> to do things.

Is a threadlocal global state part of the correct way, or is it "evil"?

> However, it sounds like the architectural design of your code is
> flawed, as throwing around the request object indicates that you don't
> have modularity.

It is legacy code. Complaining does help your soul for a short time. But after
that moment it is the same code :-)

> If you only need the user object, then why not
> replace all instances of "request=request" with "user=request.user".

Yes, that could be done. But it is not much better. I am still searching
a for a "third" way.

> The alternative is to have some magic threadlocals which stores the
> current user, but this is a particularly disgusting way of writing
> code and I could not recommend it at all.
>
> It would be better if you could explain a little more about how/where
> this request object is being passed around, then we'd be in a better
> position to give you the correct advice.

Example:

You have an instance method to render one row of a search result (a custom paginator).

One column of this row displays a link. Some users are allowed to follow the link,
some are not. You need to check the (row level) permissions before displaying it as
link or as plain text.

The render_row() method is deep inside OOP python code. The method needs to
know which user is logged in to return the correct result.

Of course I could always return a hyperlink. And users which don't have
the permission will see the permission denied page. But this is not user friendly.

Can you understand this use case?

Regards,
Thomas Güttler


--
Thomas Guettler, http://www.tbz-pariv.de/
Bernsdorfer Str. 210-212, 09126 Chemnitz
TBZ-PARIV GmbH Geschäftsführer: Dr. Reiner Wohlgemuth
Sitz der Gesellschaft: Chemnitz Registergericht: Chemnitz HRB 8543

--
Thomas Güttler
http://thomas-guettler.de/

Cal Leeming

unread,
Mar 27, 2015, 12:16:49 PM3/27/15
to django...@googlegroups.com
Hmm this all sounds quite dirty :/

However if you absolutely want to have a global object, you could try
something like [1], although I don't recommend it at all. There are
some situations where your modelling needs request introspection, for
example row level auditing, but these are very specific situations and
most of the time it's just outright abuse/bad code.

If you're using template tags and performing rendering within Django,
then you are already doing things the wrong way [2], unless your
application has a heavy SEO requirement. Sadly this is where the
weaknesses of Django, and indeed many other web frameworks, start to
appear. As such, you probably shouldn't be worrying too much about the
"passing state around being ugly", because the code is already
architecturally flawed and inherently ugly to start with. Also,
abusing globals starts to get real ugly when you introduce co-routines
and overall makes for much less readable code (imho).

Cal

[1]: http://nedbatchelder.com/blog/201008/global_django_requests.html
[2]: http://en.wikipedia.org/wiki/Single-page_application
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users...@googlegroups.com.
> To post to this group, send email to django...@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/55157785.20505%40tbz-pariv.de.

Stephen J. Butler

unread,
Mar 27, 2015, 2:06:36 PM3/27/15
to django...@googlegroups.com
On Fri, Mar 27, 2015 at 10:30 AM, Thomas Güttler <h...@tbz-pariv.de> wrote:
> You have an instance method to render one row of a search result (a custom
> paginator).
>
> One column of this row displays a link. Some users are allowed to follow the
> link,
> some are not. You need to check the (row level) permissions before
> displaying it as
> link or as plain text.
>
> The render_row() method is deep inside OOP python code. The method needs to
> know which user is logged in to return the correct result.
>
> Of course I could always return a hyperlink. And users which don't have
> the permission will see the permission denied page. But this is not user
> friendly.

How important is it that the legacy code retain the same structure?
You have the choice here to either break Django or refactor your
legacy code. Doing the refactor is what will cause you the least
headaches as you move forward (and as Django moves forward).

What you really need to do here is move render_row into a template
include or a template tag (which gets the template context, which
includes user). That's the proper place for it IMHO in the MVC
paradigm, which is the Django way.

Thomas Güttler

unread,
Apr 1, 2015, 4:37:11 AM4/1/15
to django...@googlegroups.com
Am 27.03.2015 um 17:16 schrieb Cal Leeming:
> Hmm this all sounds quite dirty :/
>
> However if you absolutely want to have a global object, you could try
> something like [1], although I don't recommend it at all. There are
> some situations where your modelling needs request introspection, for
> example row level auditing, but these are very specific situations and
> most of the time it's just outright abuse/bad code.

No, I don't want to use a global object. I am still searching for
a way that I like.



> If you're using template tags and performing rendering within Django,
> then you are already doing things the wrong way [2], unless your
> application has a heavy SEO requirement.

What is a better way?



> Sadly this is where the
> weaknesses of Django, and indeed many other web frameworks, start to
> appear. As such, you probably shouldn't be worrying too much about the
> "passing state around being ugly", because the code is already
> architecturally flawed and inherently ugly to start with. Also,
> abusing globals starts to get real ugly when you introduce co-routines
> and overall makes for much less readable code (imho).

Yes, I think co-routines make this worse.

Regards,
Thomas Güttler

--

Thomas Güttler

unread,
Apr 1, 2015, 4:44:30 AM4/1/15
to django...@googlegroups.com


Am 27.03.2015 um 19:05 schrieb Stephen J. Butler:
> On Fri, Mar 27, 2015 at 10:30 AM, Thomas Güttler <h...@tbz-pariv.de> wrote:
>> You have an instance method to render one row of a search result (a custom
>> paginator).
>>
>> One column of this row displays a link. Some users are allowed to follow the
>> link,
>> some are not. You need to check the (row level) permissions before
>> displaying it as
>> link or as plain text.
>>
>> The render_row() method is deep inside OOP python code. The method needs to
>> know which user is logged in to return the correct result.
>>
>> Of course I could always return a hyperlink. And users which don't have
>> the permission will see the permission denied page. But this is not user
>> friendly.
>
> How important is it that the legacy code retain the same structure?

This is not important. As long as the result does not change.

> You have the choice here to either break Django or refactor your
> legacy code. Doing the refactor is what will cause you the least
> headaches as you move forward (and as Django moves forward).
>
> What you really need to do here is move render_row into a template
> include or a template tag (which gets the template context, which
> includes user). That's the proper place for it IMHO in the MVC
> paradigm, which is the Django way.

ok, this way is better than the current: pass around the context
everywhere where the request gets passed around up to now.

Headache makes the code which gets called outside the request-response cycle.
For example cron jobs.

Example: We create reports for users in cron jobs. Here we need a user object
and have no context.

Regards,
Thomas Güttler

--
Thomas Güttler
http://thomas-guettler.de/

Cal Leeming

unread,
Apr 1, 2015, 8:40:40 AM4/1/15
to django...@googlegroups.com
On Wed, Apr 1, 2015 at 9:36 AM, Thomas Güttler <h...@tbz-pariv.de> wrote:
> Am 27.03.2015 um 17:16 schrieb Cal Leeming:
>>
>> Hmm this all sounds quite dirty :/
>>
>> However if you absolutely want to have a global object, you could try
>> something like [1], although I don't recommend it at all. There are
>> some situations where your modelling needs request introspection, for
>> example row level auditing, but these are very specific situations and
>> most of the time it's just outright abuse/bad code.
>
>
> No, I don't want to use a global object. I am still searching for
> a way that I like.
>
>
>
>> If you're using template tags and performing rendering within Django,
>> then you are already doing things the wrong way [2], unless your
>> application has a heavy SEO requirement.
>
>
> What is a better way?

Have a read of the link I gave regarding SPAs. If you look on Google
for Single Page Applications, you'll see a lot of it explained
already. This is one of the primary reasons why Django, and many other
frameworks, are doing it wrong. That being said, doing things properly
is quite hard and requires you to have a good amount of JS/ES5
knowledge.

>
>
>
>> Sadly this is where the
>> weaknesses of Django, and indeed many other web frameworks, start to
>> appear. As such, you probably shouldn't be worrying too much about the
>> "passing state around being ugly", because the code is already
>> architecturally flawed and inherently ugly to start with. Also,
>> abusing globals starts to get real ugly when you introduce co-routines
>> and overall makes for much less readable code (imho).
>
>
> Yes, I think co-routines make this worse.
>
> Regards,
> Thomas Güttler
>
> --
> --
> Thomas Güttler
> http://thomas-guettler.de/
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users...@googlegroups.com.
> To post to this group, send email to django...@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/551BAE1B.2040605%40tbz-pariv.de.

Stephen J. Butler

unread,
Apr 1, 2015, 12:01:16 PM4/1/15
to django...@googlegroups.com
On Wed, Apr 1, 2015 at 3:43 AM, Thomas Güttler <h...@tbz-pariv.de> wrote:
> Headache makes the code which gets called outside the request-response
> cycle.
> For example cron jobs.
>
> Example: We create reports for users in cron jobs. Here we need a user
> object
> and have no context.

You still have a Context object; you always have one if you're in the
render phase. Your context just won't be a RequestContext object, so
the hooks in TEMPLATE_CONTEXT_PROCESSORS won't know how to get "user".

But when you create the Context yourself you can pass in whatever
value for "user" is appropriate. Your templates won't know the
difference between rendering in a cron, management command, or request
cycle.

https://docs.djangoproject.com/en/1.7/ref/templates/api/#rendering-a-context
Reply all
Reply to author
Forward
0 new messages