web2py / py4web

Other
242 stars 126 forks source link

@action.uses(NewFixture({"application/csv": to_csv})) #378

Closed tomcam closed 2 years ago

tomcam commented 3 years ago

From today's chat:

Imagine you have an action def get_data(): that returns dict(). You would create a new

@action('get_data.csv') 
def get_data_csv(): 
    return to_csv(get_data())

The proposed decorator would allow you to piggy back the latter to the former.

@action.uses(NewFixture({"application/csv": to_csv}))

If the request asks for content_type - "application/csv" the dict() would be filtered by to_csv

valq7711 commented 3 years ago

Suppose there are some default built-in renders that shipped with py4web, but can be overwritten for whole app The cases:

mdipierro commented 3 years ago

Why do we need both "renders" and "Fitting"?

valq7711 commented 3 years ago

Fitting does nothing, it's required to indicate that result is not just a dict but is structured for renders. Of course we can follow the convention like if renders in fixtures then dict is structured but in that case, if we remove renders due to some reasons we also have to change the result dict. Fitting is intendend to strucure response, renders - to process it, using both allows to decouple one from the other

valq7711 commented 3 years ago

Maybe just Fit instead of Fitting, so return dict(...) is a shortcut for return Fit(html =dict( ...))

jpsteil commented 3 years ago

The need for me is the following:

I am creating a Vue grid. I want to use only one controller function to:

  1. build the html/css/js for the Vue grid
  2. provide the json to populate the grid from my fetch()

I'm getting around this right now by just redirecting to a different controller function that returns json and not a template.

My opinion is that it would make sense to have it in the method 'return' somehow instead of putting it in a fixture.

Following Val's 'Fitting' idea, I think it would be great if it defaulted to using

return Fitting(html=template_from_the_fixture)

But you could override by saying:

return Fitting(json=json_data)

Here is my controller method as I see it using Val's method:

@action('vue_customer_type')
@action.uses(session, db, auth.user,
             Inject(title='Applications', subtitle='Customer Types'),
             'vue_grid.html')
def vue_customer_type():

    search_queries = [GridSearchQuery(name='Filter by Name',
                                      query=lambda value: db.customer_type.name.contains(value),
                                      requires=None)]

    columns = [GridColumn(db.customer_type.id, show_in_grid=False),
               GridColumn(db.customer_type.name)]

    vg = VueGrid(request.url
                 fields=['customer_type.id', 'customer_type.name'],
                 columns=columns,
                 orderby='customer_type.name',
                 search_queries=search_queries)

    if request.query.get('@offset') and request.query.get('@limit'):
        #  user is requesting json data
        return Fitting(json=vg.request_data(request))

    return dict(vue_grid=vg)

If using the AllowedTypes in a fixture, I don't see how I'd specify on my return statement which one I want to use in a specific instance.

mdipierro commented 2 years ago

I think this is overly complicated. Most people will simply register multiple actions based on the URL extension and filter based on that, not the content-type.