Filter records according to zone (user table field) user

Hello,
Is it possible to create a class in views.py that filters the records based on the user accessing it?
I don’t want it to filter according to admin or not (which I already have) but to filter according to the zone (field of the users table) that the user belongs to. For its part, the record also has a zone field. The thing would be to show zone 1 records to zone 1 users, zone 2 to zone 2 users…
I currently have the following generic view:

class ListadoReclamacion(ListView):
    model = Rec

    def get_queryset(self):
        return self.model.objects.filter(estado_cod_id=1)

    def get(self,request,*args,**kwargs):
        request.headers.get('x-requested-with') == 'XMLHttpRequest'
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            return HttpResponse(serialize('json',self.get_queryset()),'application/json')
        else:
            return redirect('inicio_reclamaciones')

thank you

Absolutely.

A CBV makes the request available as an attribute of the view. This means that you have access to self.request.user in all functions within that CBV.

Side note: In addition to the official docs for class-based views, I also recommend the Classy Class-Based Views site and the CBV diagrams page for enhancing your understanding of how CBVs work. I strongly encourage you to become familiar with both of these resources.

Thanks for the information, I have been reading it and today I will read it again to understand more. One thing I wanted to ask, I already managed to filter the view according to some filters indicated in a queryset, but I would like to go further and apart from the filters according to a series of fields I would also like to filter the records depending on the user.
Example,
Firstly I filter the view according to field =1 but I want to add that if the user is =1 it shows it, if the user is =2 it doesn’t.

def get_queryset(self):
        return self.model.objects.filter(campo1=1,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)

Sorry, I didn’t mean that. The thing is different.
I already have the records filtered according to the field and according to the user it shows it or not but what I don’t know how to do is the following:

If I access with user=1 and it shows the record, there must be a button that goes to a view

If I access with user=2 and it shows the record, there must be a button that goes to a different view than that of user 1

I don’t know if you understood me.

Going to a different view is different than filtering a single view based upon the user.

In this case, you can change the url being rendered for the button based upon the user viewing the page.

Other than just saying “user = 1” or “user = 2”, is there some attribute of the user that you can use to determine which view is called?

How are you currently rendering the button?

Well that would be the idea, according to the user, modify the url of the button, which in the end would be the view. Because I have two different views that would be one for each user.

url button 1 does one thing
url button 2 does something else

Yes, there is another field that I want to use for this, it is a field of 0 or 1.

Currently there is only one view created for the two types of user, what I do before is make a queryset that filters data for me.

function listadoReclamaciones(){
    $.ajax({
        url: "/reclamaciones/listado_reclamaciones/",
        type:"get",
        dataType: "json",
        success: function(response){
            if($.fn.DataTable.isDataTable('#tabla_reclamaciones')){
                $('#tabla_reclamaciones').DataTable().destroy();
            }
            $('#tabla_reclamaciones tbody').html("");
            for(let i = 0;i < response.length;i++){
                let fila = '<tr>';
                fila += '<td>' + (i +1) + '</td>';
                fila += '<td>' + response[i]["fields"]['num_reclamacion'] + '</td>';
                fila += '<td>' + response[i]["fields"]['motivo'] + '</td>';
                fila += '<td>' + response[i]["fields"]['fecha_reclamacion'] + '</td>';
                fila += '<td>' + response[i]["fields"]['aprueba'] + '</td>';
                fila += '<td>' + response[i]["fields"]['del_dep_code'] + '</td>';
                fila += '<td>' + response[i]["fields"]['estado_cod'] + '</td>';
                fila += '<td><button type = "button" class = "btn btn-primary btn-sm tableButton" ';
                fila += 'onclick = "abrir_modal_edicion(\'/reclamaciones/actualizar_reclamacion/' + response[i]['pk']+'/\');"> EDITAR </button>';
                fila += '<button type = "button" class = "btn btn-primary btn-sm tableButton" ';
                fila += 'onclick = "window.location.href=\'/reclamaciones/enviar_para_aprobar/' + response[i]['pk']+'/\'"> ENVIAR </button>';
                fila += '</td>';
                fila += '</tr>';
                $('#tabla_reclamaciones tbody').append(fila);
            }

View where I see what user it is, if it is 3 I make a query but another. But of course, the record view makes it perfect for me but the button is the same, which I don’t want.

class ListadoReclamacion(ListView):
    model = Rec

    def get_queryset(self):
        if self.request.user.cod_cargo_id==3:
            return self.model.objects.filter(estado_cod=4,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)
        else:
            return self.model.objects.filter(estado_cod=1,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)

Instead of constructing that url location in the template, construct it as part of the view and return it in the response object.

In the view you can determine what the url should be based upon the user requesting the view and add that attribute accordingly.

I do not understand very well, the serious thing is that in the view:

  • determine user
  • according to that user save url in object
  • add object with url in template

it would be like this?

I can’t find much about how to save url according to user in an object to be able to pass later to the onclick of the button
Might you help me?

Basically, yes.

Ignore the full url for a moment.

If you wanted to set some value based upon the type of user, how would you do that?

Let’s say you have a variable named button. You want button to be /one-thing for user type 1, and /something-else for user type 2.

What would your code look like for that? (Just for this - don’t worry about anything else right now.)

I do not understand what you mean

The truth is that I don’t know how to continue, I’ve been trying for a few days but I don’t see how.
Could you guide me a bit?

Hello, how could I adapt this part of code in my views.py?

I currently have this:

class ListadoReclamacion(ListView):
    model = Rec

    def get_queryset(self):
        if self.request.user.cod_cargo_id==3:
            return self.model.objects.filter(estado_cod=4,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)
        else:
            return self.model.objects.filter(estado_cod=1,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)

    def get(self,request,*args,**kwargs):
        request.headers.get('x-requested-with') == 'XMLHttpRequest'
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            return HttpResponse(serialize('json',self.get_queryset()),'application/json')
        else:
            return redirect('inicio_reclamaciones')

I want to add something like this:

def lista(request):
    es_jefe = request.user.cod_cargo_id==3
    return render(request, "lista.html",{"es_jefe":es_jefe,})

The thing is that unlike this code that goes to an html page which is where it shows the records, buttons… In my case, as I said before, I bring the records from DataTable, I don’t know how it should be indicated in the part of the render

So lets come back to the basics here.

Yes, I understand what you’re current view (ListadoReclamacion) is doing.

What I am understanding what you want to do, is to change the JSON response being returned by that view to include one of two urls to be rendered in your page by your JavaScript, to change the value currently being rendered by this line:

If my understanding is correct, then I come back to my earlier question.

What is your Python code to figure out which of the two URLs to use?
(I’d be expecting to see an if statement here. And again, I’m asking you to ignore all other issues at the moment. I only want to see the code that will choose between the two URLs.)

I would do something like that although I don’t know exactly how.

if self.request.user.cod_cargo_id==3:
     send url
else:
    send another url

Great! Now, instead of writing “send url” and “send another url”, what are the actual URLs that you want to use? (What are “url” and “another url” going to be?)

The configured URLs are for
user 1: 'reclamaciones/enviar_para_aprobar/<int:pk>/'

user 2: 'reclamaciones/aprobar_reclamacion/<int:pk>/'

Cool.

Now, in your view, you have:

The first change I would suggest is this:

    def get_queryset(self):
        if self.request.user.cod_cargo_id==3:
            queryset = self.model.objects.filter(estado_cod=4,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)
        else:
            queryset = self.model.objects.filter(estado_cod=1,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)

Now that you have the queryset object in this function, you can iterate over the queryset to add additional attributes to the individual elements. Copying your code from your previous responses:

.... continued from above
for instance in queryset:
    if self.request.user.cod_cargo_id==3:
      instance.url = reverse('name_of_url_1', args=[instance.pk])
    else:
      instance.url = reverse('name_of_url_2', args=[instance.pk])

return instance

… where name_of_url_1 is the name attribute for the url defined as reclamaciones/enviar_para_aprobar/<int:pk>/ and name_of_url_2 is the name attribute of the other url.

How do I pass get_queryset to my view?
Until now I had my class
In the part of the def get…in the line

return HttpResponse(serialize('json',self.get_queryset()),'application/json')

I passed a json self.get_queryset()
That in theory would no longer be like that, right?

resulting code

class ListadoReclamacion(ListView):
    model = Rec

    def get_queryset(self):
        if self.request.user.cod_cargo_id==3:
            queryset = self.model.objects.filter(estado_cod=4,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)
        else:
            queryset = self.model.objects.filter(estado_cod=1,del_dep_code=self.request.user.cod_delegacion_zona.cod_delegacion)
        
        for instance in queryset:
            if self.request.user.cod_cargo_id==3:
                instance.url = reverse('aprobar_reclamacion', args=[instance.pk])
            else:
                instance.url = reverse('enviar_para_aprobar', args=[instance.pk])
            return instance

    def get(self,request,*args,**kwargs):
        request.headers.get('x-requested-with') == 'XMLHttpRequest'
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            return HttpResponse(serialize('json',self.get_queryset()),'application/json')
        else:
            return redirect('inicio_reclamaciones')

First, your return instance statement is indented too far. It needs to be at the “main” level of your code in that function. (At the same level of indentation as the for statement, not indented within it.)

No, you haven’t fundamentally changed get_queryset. As a function, it’s returning a queryset.

Side notes:

This line is useless and can be removed.


This would be more appropriate if you changed it to return a JsonResponse instead of an HttpResponse.