7

How to redirect url from middleware?

Infinite loop problem.

I intend to redirect the user to a client registration url if the registration has not yet been completed.

def check_user_active(get_response):
    def middleware(request):
        response = get_response(request)

        try:
            print(Cliente.objects.get(usuario_id=request.user.id))
        except Cliente.DoesNotExist:
            return redirect('confirm')


        return response
    return middleware
marcelo.delta
  • 2,730
  • 5
  • 36
  • 71

2 Answers2

8

Every request to server goes through Middleware. Hence, when you are going to confirm page, the request goes through middleware again. So its better put some condition here so that it ignores confirm url. You can try like this:

def check_user_active(get_response):
    def middleware(request):
        response = get_response(request)
        if not request.path == "confirm":
            try:
                print(Cliente.objects.get(usuario_id=request.user.id))
            except Cliente.DoesNotExist:
                return redirect('confirm')
        return response
    return middleware
ruddra
  • 50,746
  • 7
  • 78
  • 101
  • This is actually a very bad idea! Is true it answers the OP's question, but it hides very bad practices and design. I personally won't recommend nobody to use code like this in production, this code will carry an extra database query for every request even if the URL being visited does not require the user to be registered. – Raydel Miranda Jun 21 '23 at 06:27
  • That is not true regarding DB call, it does not query on every request because it checks for path first. Yes, it will be difficult for you to debug if you are not aware of the business logic also where the code is (requires a very good documentation). But it does not break DRY principle and also very concise code which takes care of a business logic for several views or pages, otherwise it would have taken many repetition. FYI, I just noticed your answer here but I did not downvote you. – ruddra Jun 21 '23 at 07:04
  • You're right. Not for every request that query is carried out. On the other hand, I did not downvote yours because I think you did downvote mine, I swear. I downvote your answer to express I wouldn't recommend that solution. – Raydel Miranda Jun 21 '23 at 13:41
0

Update

Despite the downvotes, I still do not recommend using middleware for the specific use case of "redirecting if no registration is complete".

It is a bad idea just to execute that logic for every URL in your application. Even if the user does not need registration, for instance, pages like: "About US", "Q&A", "Home", etc ...

Even worst, taking into account that logic involves a database query!

It is a better solution (even if not what the OP is specifically asking for, in the spirit of SO I am obligated to share it) to create a decorator (just like the one for login_required) to be used in the views you want to ensure the user has finished the registration.

def registration_completed(user):
    # Implement your logic to check if registration is completed for the user.
    # This can be done by checking a specific field or condition in the user model
    # For example, if there is a "registration_completed" field in the User model.

    # I will use in the meantime the exact same logic you have in your code.

    try:
        Cliente.objects.get(usuario_id=request.user.id)
    except Cliente.DoesNotExists:
        return False

    return True
    

def registration_required(func):
    @wraps(func)
    def wrapper(request, *args, **kwargs):
        if not registration_completed(request.user):
            return redirect('registration_completion')  # Redirect to registration completion page if registration is not complete
        return func(request, *args, **kwargs)
    return wrapper

Now achieving what you want is as easy as decorating just the views that you need the user is registered for being able to use:

@registration_required
def my_view(request):
    # Your view code here

You should be using a login_required like decorator see Django authentication system for more detail.

Example:

from django.contrib.auth.decorators import login_required

@login_required(login_url="/your/login/view/url/")
def my_view(request):
    ...

Avoid using middlewares for any kind of redirection always you can, according to the docs

Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.

In other words, middlewares are there for processing request and responses, if you redirect to any view, you will (potentially) recursively trigger your middleware.

And, on the other hand ...

In the future, you might want to add a view that can be visited by anonymous users, this middleware will be a problem ...

Raydel Miranda
  • 13,825
  • 3
  • 38
  • 60