django-sql-explorer icon indicating copy to clipboard operation
django-sql-explorer copied to clipboard

Embedding a query

Open spapas opened this issue 2 years ago • 0 comments

Hello friends, in a recent project I wanted to embed a query in a view for all users to be able to run it. So instead of using the provided views I wanted to properly embed the report in my views so as to use my permissions etc (the requirement was a little more complex than that but it doesn't matter).

I didn't find any docs for that so I had to research the source code and use the query_viewmodel function. So, my query detail view is similar to this:


from explorer.models import Query
from explorer.views.utils import query_viewmodel

class QueryDetailView(DetailView):
    template_name = "reports/query_detail.html"
    model = Query

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        query = self.get_object()
        query.params = dict(
            [(k[:-6], v) for k, v in self.request.GET.items() if k.endswith("_param")]
        )

        vm = query_viewmodel(self.request, query)

        # dict_keys(['tasks_enabled', 'params', 'title', 'shared', 'query', 'form', 'message', 'error', 'rows', 'data', 'headers', 'total_rows', 'duration', 'has_stats', 'snapshots', 'ql_id', 'unsafe_rendering', 'fullscreen_params'])
        context.update(vm)
        context["title"] = query.title
        return context

Then I used a query_detail.html template like:


{% extends "site_base.html" %}
{% block page_content %}

{% if params %}
<form method='GET'>
    <div class="form-inline">
        {% for k, v in params.items %}
            <div class="form-group">
                <label for="{{ k }}_param" class="control-label col-sm-4">{{ k }}:</label>
                <div class="col-sm-7">
                    <input type="text" data-param="{{ k }}" class="param form-control" name="{{ k }}_param" id="{{ k }}_param" placeholder="parameter" value="{{ v }}" />
                </div>
                <div class="col-sm-1"></div>
            </div>
        {% endfor %}
    </div>
    <input type='submit' class='btn btn-primary' value='Query'>
    <a href='{{ request.path }}' class='btn btn-secondary'>Reset</a>
</form>
{% endif %}

<div class="row">
    <div class="col-md-12">
        {% if data %}
            <table class='table'>
                <thead>
                    <tr>
                        {% for col in headers %}
                            <th>{{ col }}</th>
                        {% endfor %}
                    </tr>
                </thead>
                <tbody>
                    {% for row in data %}
                        <tr>
                            {% for col in row %}
                                <td>{{ col }}</td>
                            {% endfor %}
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        {% endif %}
    </div>
</div>
{% endblock %}

I'm not sure if this is the correct way to do it, can you please confirm. If yes, I'd recommend adding this in the documentation so it's easy for other users that want to embed queries. Also we may want to make the query_viewmodel function as part of the API so we should describe its inputs/outputs.

I can provide the PR with the change to the docs if you think it will be useful.

spapas avatar Aug 30 '22 07:08 spapas