How to add an attribute to request like the 'user' variable

Viewed 1125

I want to create a new variable which is always available like how the 'user' variable works.

Here is my myapp/context_processors.py

def patient_selected(request):

print(hasattr(request, 'patient_selected_id'))
print( 'patient_selected_id' in locals())
print( 'patient_selected_id' in globals())

if not hasattr(request, 'patient_selected_id'):
    request.patient_selected_id = 0

return {"patient_selected_id": 0}

The problem is, it always prints 'false'. It seems like I cannot add an attribute to the request, nor create a variable constantly available. BTW, I have added this context_processors.py to settings. Here is my setting:

TEMPLATES = [
{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [],
    'APP_DIRS': True,
    'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
            'hrs.context_processors.patient_selected',
        ],
    },
},

]

EDIT: After reading source codes, it seems like the user variable is not actually created once and live forever. The Middleware and context_processor add a variable user for every request, and this 'user' is actually pulled from session.

My original design is: Once a patient is selected, all following pages will be about this patient. Thus, I would like to make this patient's id always available. Instead of pass this id all around, I want to save it(somewhere) once and always available until another patient is selected.

However now, considering the complexity of user variable, I may give up the fancy way. Simply put this id as a parameter in every request url should be easier.

1 Answers

Django does that with middleware [Django-doc]. In fact setting the .user attribute is done with middleware as well. Indeed, you can see this in the AuthenticationMiddleware [GitHub]:

class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        assert hasattr(request, 'session'), (
            "The Django authentication middleware requires session middleware "
            "to be installed. Edit your MIDDLEWARE%s setting to insert "
            "'django.contrib.sessions.middleware.SessionMiddleware' before "
            "'django.contrib.auth.middleware.AuthenticationMiddleware'."
        ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
        request.user = SimpleLazyObject(lambda: get_user(request))

If you remove the 'django.contrib.auth.middleware.AuthenticationMiddleware' string from the MIDDLEWARE setting [Django-doc], then the request.user will no longer be set.

You can thus implement your own middleware. For example with:

# app/middleware.py

from django.utils.deprecation import MiddlewareMixin

class PatientSelectIdMiddleware(MiddlewareMixin):

    def process_request(self, request):
        if not hasattr(request, 'patient_selected_id'):
            request.patient_selected_id = 0

Next you need to add the 'app.PatientSelectIdMiddleware' middleware to the MIDDLEWARE setting.

Related