Hello,
class ShowCargoPais(SingleTableMixin, ExportMixin, FormView):
form_class = CargoPaisForm
template_name = "form.html"
table_class = CargoPaisTable
table_data = pcf.objects.all().using("db")
table_pagination = False
export_name = "cargoPais"
extra_context = {"name": "Cargo Funcional Por Pais"}
def form_valid(self, form):
paises = form.cleaned_data["paises"].split(",")
self.table_data = pcf.objects.filter(pai__in=paises).using("db").values()
additional_data = {"table": self.get_table()}
return render(self.request, "tableAutoExport.html", context=additional_data)
The code above works but there are several issues:
- If the attribute table_data=None at the start the get_table_data method crashes as it is trying to get thedata which still has not been correctly generated. The data will be correctly generated in the form_valid method which will use the form data to get the correct objects. The current attribute setting is a placeholder to prevent this.
- The second issue is that the export exports the initial table_data not the one modified by the form_valid method.
- The third and less important is that the SingleTableMixin method that should add the table to context automatically but doesn’t.
Is there any change that can be made to fix this. I believe the issue is related with the get_table_data method running to early during the get request.
This is using django-tables 2. This is a link to the singletablemixin django-tables2/views.py at master · jieter/django-tables2 · GitHub.
Thanks,
Code that runs at the class level only runs once, and that’s when the class is imported.
So this line:
musn’t be in it’s current location. If that’s something that is going to be needed in the context, it should be in get_context_data
.
I see you also have basically the same query in form_valid
. Do you really need both definitions for that?
Is this the entire view, or are there other functions here that you trimmed out?
Also, please post your template - simply adding something in the context does not automatically mean it’s going to be rendered on the page. It must also be defined there. If what’s identified in the template doesn’t match the name used in the context, you won’t see anything.
Hello,
That is the entire view no functions are left out. The issue with not defining the table_data as an attribute or setting it equal to non is that triggers a error from the SingleTableMixin from the get_data method. It made sense to me to leave it as none and later define it in the form_valid method but this would cause an error.
The following are the form and tableAutoExport templates:
tableAuto
{% extends 'base.html' %}
{% load django_tables2 %}
{% block content %}
<h1>Results</h1>
<button><a href={% export_url "csv" %}>Export</a></button>
{% render_table table%}
{% endblock %}
form
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% block content %}
<h1>{{ name }}</h1>
<div class=form>
<form method="post">
{% csrf_token %}
<table>
{{form.as_table}}
<table>
<input type="submit" value="Search">
<form>
</div>
{% endblock %}
Thanks
Hello,
I am trying to work around the issue.However,when using form.is_valid inside get_table_data I get false but when called from form_valid it is true. Why?
class ShowCargoPais(SingleTableMixin, ExportMixin, FormView):
form_class = CargoPaisForm
template_name = "form.html"
table_class = CargoPaisTable
table_data = pcf.objects.all().using("db")
table_pagination = False
export_name = "cargoPais"
extra_context = {"name": "Cargo Funcional Por Pais"}
def get_table_data(self):
form = self.get_form()
print(form.is_valid())
print(form)
data = pcf.objects.all().using("ofp1")
return data
def form_valid(self, form):
paises = form.cleaned_data["paises"].split(",")
self.table_data = pcf.objects.filter(pai__in=paises).using("db").values()
additional_data = {"table": self.get_table()}
return render(self.request, "tableAutoExport.html", context=additional_data)
This issue would be generally resolved by overriding the get_data
method to set that value before calling super in that method. It’s never the right answer to issue a query at the class level.
The issue with your templates is that the {% block content %}
block in your form template overwrites (replaces) the block defined in base.html. That means that none of this:
is going to get rendered.
Hello,
class ShowCargoPorPais(SingleTableMixin, ExportMixin, FormView):
form_class = CargoPorPaisForm
template_name = "form.html"
table_class = CargoPorPaisTable
table_pagination = False
export_name = "cargoPais"
extra_context = {"name": "Cargo Funcional Por Pais"}
def get_table_data(self):
form = self.get_form()
if form.is_valid():
self.request.session["CargoPorPaisForm"] = form.cleaned_data
paises = form.cleaned_data["paises"].split(",")
self.table_data = (
pcf.objects.filter(pai__in=paises).using("db").values()
)
elif self.request.GET.get("_export"):
form.cleaned_data = self.request.session["CargoPorPaisForm"]
paises = form.cleaned_data["paises"].split(",")
self.table_data = (
pcf.objects.filter(pai__in=paises).using("db").values()
)
else:
self.table_data = {}
return self.table_data
def form_valid(self, form):
additional_data = {"table": self.get_table()}
return render(self.request, "tableAutoExport.html", context=additional_data)
This seems to work. Are there any pitfalls to this? The issue seems to be that the get_table_method runs each time : when shown the form, when seeing the results and when exporting. For each of these cases something had to be done in the get_table_data method. The first is for the case after the form is filed and therefore valid. This stores the form data in the request session. Then the case when clicking on the export button uses the fact that the request has a query string and data stored from the form in the sessions variable. The last case occurs when first seeing the form a empty dictionary is sent to prevent the error.
Thanks,
I don’t see any fundamental pitfalls to this.
I’d take a different approach, but it’s a personal choice, not that one is “better” or “more correct” than the other, and it really depends upon what your ultimate objective is here.
If the purpose of the Export
button is to create a file to be downloaded, I’d set up the export
button to call a different view that returns a FileResponse
object to have the data directly sent to the browser as a file.
(If the actual intent is different, then my answer would change.)
Hello,
Yes had used that approach previously. Each export button had a view that returned a file object. However, that was with function based views . I thought with class based views it would be better but it is exactly the same.
A class-based view is still just a view. It’s still a function (as_view
). It’s just that the code is organized into a class to help reduce the repetitive code commonly found when creating views with a common pattern. Once you’re extending a view beyond the pattern they’re designed to support, they provide fewer benefits.