iommirocks / iommi

Your first pick for a django power cord
http://iommi.rocks
BSD 3-Clause "New" or "Revised" License
803 stars 51 forks source link

Get request.user in Page and Table views #558

Closed wdelport-sgi closed 3 months ago

wdelport-sgi commented 3 months ago

Thanks for developing this very useful package. It would be great if you could help with a use case that I am trying to solve.

Briefly, I have a Page view - something like:

class ReviewPage(Page):
  table_1 = Table1()
  table_2 = Table2()

where table_1 and table_2 are EditTables that load different query sets from the same model, i.e

class Table1(EditTable):
  class Meta:
    auto__model = myModel
    rows = myModel.objects.filter(approved=False)

class Table2(EditTable):
  class Meta:
    auto__model = myModel
    rows = myModel.objects.filter(approved=True)

The issue I am trying to solve for is to add a request.user based filter on the querysets above. To do this I can wrap the ReviewPage in a view wrapper, i.e.

def reviewpage_view(request):
  context = {'username': request.user}
  return ReviewPage(context=context)

But I am not sure how to ensure the request info gets passed on to the Tables, so I can do

class Table1(EditTable):
  class Meta:
    auto__model = myModel
    rows = myModel.objects.filter(approved=False, user__username=username)

I have tried a self.get_request() on the Table classes and that is null.

Do you have any suggestions on how to achieve this?

Thanks

boxed commented 3 months ago

Trying to fetch the request in the table definition would mean that the code tries to get the request at import time, which of course can't work as you say. You need to pass a function:

class Table1(EditTable):
  class Meta:
    auto__model = myModel
    rows = lambda user, **_: myModel.objects.filter(approved=False, user=user)

This is a general pattern and there's a lot of useful things passed into these lambdas. You can easily find out which things are passed by writing some garbage as a parameter name (like asdasdasd), where you will get a nice error message with all the options.

wdelport-sgi commented 3 months ago

Thanks; that is clear now. I ended up needing to do something a little more complicated with the query set, so I wrapped that up in a method called below, i.e.

def get_queryset(username):
    # do complex queryset filterting and collect instances
    return queryset

class Table1(EditTable):
    class Meta:
        auto__model = myModel
        rows = lambda user, **_: get_queryset(user)
boxed commented 3 months ago

You could simplify that a bit more:

def get_queryset(user, **_):
    # do complex queryset filterting and collect instances
    return queryset

class Table1(EditTable):
    class Meta:
        auto__model = myModel
        rows = get_queryset

You don't need the lambda, if you just add ** to the signature of the function.

jlubcke commented 3 months ago

Or even:

class Table1(EditTable):
    class Meta:
        auto__model = myModel

        @staticmethod
        def rows(user, **_):
            # do complex queryset filterting and collect instances
            return queryset = get_queryset