Django - Reduce URL query-string length - django

I been working with Django Forms for a while but recently I had to create a form to search for data with a MultipleChoiceField.
Since the URL must be shared between the users the form performs a GET to the server to keep the search parameters in the query-string.
The problem is that if multiple options are checked the length of the URL increases too much. For example:
http://www.mywebsite.com/search?source=1&source=2&source=3...
Is there anyway working with django forms to get a url like the following:
http://www.mywebsite.com/search?source=1-2-3...
Or is it a better approach to create a token that compress the query-string parameters?
The form is then used to make a search over ElasticSearch. I'm not using djangos models.
Thanks!

Overriding get and get_context_data on a TemplateView could work. Then you could have a URL like this: http://www.mywebsite.com/search?sources=1,2
class ItemListView(TemplateView):
template_name = 'search.html'
def get(self, request, *args, **kwargs):
sources = self.request.GET.get('sources')
self.sources = sources.split(',') if sources else None
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.sources:
context['search-results'] = self.get_search_results(
self.sources,
)
return context
def get_search_results(self, sources):
"""
Retrieve items that have `sources`.
"""
# ElasticSearch code hereā€¦
data = {
'1': 'Honen',
'2': 'Oreth',
'3': 'Vosty',
}
return [data[source_id] for source_id in sources]
Now, if the /search?sources=1,2 URL was requested the template context would have Honen and Oreth in it as the variable search-results.

Related

Django-filters resets after using the UpdateView

I have a Model with a lot of entries, so I'm using django-filters to filter the model, I initially load an empty table and from there I use the filter to view the items.
Everything works fine, the page loads initially with no entry, after I filter, django shows the correct items.
The Url gets a parameter: /retetabloc/?acordcadru=532(532 is the filter) but when I try to update an entry, the filter resets(the parameter is still in the URL) and the whole db is loaded.
I don't quite understand how to pass the filter parameter to the RetetaBlocUpdate, so that after the update is done it returns to the filtered items like in the ListView.
views.py
class RetetaBlocListview(LoginRequiredMixin, CoreListView):
model = RetetaBloc
def get_queryset(self, *args, **kwargs):
pdb.set_trace()
acordcadru = self.request.GET.get("acordcadru")
queryset = RetetaBloc.objects.filter(acordcadru=acordcadru)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = RetetaBlocFilter(self.request.GET, queryset=self.get_queryset())
pdb.set_trace()
return context
class RetetaBlocUpdate(LoginRequiredMixin, AjaxUpdateView):
model = RetetaBloc
form_class = RetetaBlocForm
Thank you.
If you'd like filters to be remembered you could add them to a session variable instead. That way filters would be recalled even if they didn't go back directly from the update page (and you'd wouldn't have redundant URL querystring on pages where they weren't needed).
Something like:
def get_queryset(self, *args, **kwargs):
pdb.set_trace()
#check for new filter in URL first
acordcadru = self.request.GET.get("acordcadru")
#if nothing check for session variable
if not acordcadru:
acordcadru = self.request.session.get('acordcadru')
#if something in URL querystring, set it in session variable
else:
self.request.session['acordcadru'] = acordcadru
queryset = RetetaBloc.objects.filter(acordcadru=acordcadru)
return queryset

Django - Filtering Field In DetailView

Hi all,
I've been building a Django app that allows users to stream and download music. However, there is one issue that I'm having with the artists profile pages; I'm trying to request the songs by the artist only in a DetailView as I'm treating it like a blog system.
Is this possible in a DetailView? Or do I need to make a filter? I've been searching the web for days now and didn't really understand what I can do or how to get the specific data field from the model.
Any help or guidance would be highly appreciated!
class musicartist(DetailView):
model = MusicArtist
template_name = 'RS_MUSIC/artist.html'
# override context data
def get_context_data(self, *args, **kwargs):
context = super(musicartist, self).get_context_data(*args, **kwargs)
# add extra field
current_band = MusicItems.objects.all().filter(artist=MusicArtist.title)[:1]
context["songs"] = MusicItems.objects.filter(artist=MusicArtist.objects.all().filter(title=current_band)[:1])
return context
Managed to figure it out. Just needed the following code:
class musicartist(DetailView):
model = MusicArtist
template_name = 'RS_MUSIC/artist.html'
def get_context_data(self, **kwargs):
context = super(musicartist, self).get_context_data(**kwargs)
context_related = MusicItems.objects.filter(artist=self.object.title)
context['related'] = context_related
return context

Django CBV ListView, accessing both paginated and unpaginated results

I built a list view using generic view class ListView with pagination and search functionality. Now I want to include in the same page a map with markers for all the results, without pagination.
Is there a way to reach both paginated and unpaginated results without having to do a duplicate query?
We can do it by override the method def get_context_data(self, **kwargs). It takes only a single query.
class MyListview(ListView):
def get_context_data(self, **kwargs):
kwargs['obj_list'] = list(kwargs['obj_list'])
my_obj_list = kwargs['obj_list']
context = super(MyListview, self).get_context_data(**kwargs)
context['my_obj_list'] = my_obj_list
return context

Do I need to use request.is_ajax() in my views?

I am learning to use Ajax with Django, many tutorials simply check if request.method == 'GET' or POST. I am curious for what do we need .is_ajax() then. Is it normal no to use it or tutorials just show basic concepts?
I am curious for what do we need .is_ajax() then. Is it normal no to
use it or tutorials just show basic concepts?
Yes, it is totally normal not to use is_ajax. Most of the time what you care about in your views is the HTTP verb (e.g. GET, POST, PATCH..).
However there are certain cases where you want to know if the request is an AJAX request. Why? because you might want to return a different result depending if the request is ajax or not.
The most common use for this solution is PJAX. When you use a pjax technology, if the request is not an ajax request you render the entire page, whereas if the request comes from ajax you render only a partial of the page. Then the partial page is added in the correct place in the webpage by some sort of lib, such as https://github.com/defunkt/jquery-pjax.
For example, this is a mixing I wrote to use Pjax in django:
import os
from django.views.generic.base import TemplateResponseMixin
class PJAXResponseMixin(TemplateResponseMixin):
pjax_template_name = None
pjax_suffix = "pjax"
pjax_url = True
def get_context_data(self, **kwargs):
context = super(TemplateResponseMixin, self).get_context_data(**kwargs)
context['inner_template'] = self.pjax_template_name
return context
def get_template_names(self):
names = super(PJAXResponseMixin, self).get_template_names()
if self.request.is_ajax():
if self.pjax_template_name:
names = [self.pjax_template_name]
else:
names = self._pjaxify_template_var(names)
return names
def get(self, request, *args, **kwargs):
response = super(PJAXResponseMixin, self).get(request, *args, **kwargs)
if sel
f.pjax_url :
response['X-PJAX-URL'] = self.request.path
return response
def _pjaxify_template_var(self, template_var):
if isinstance(template_var, (list, tuple)):
template_var = type(template_var)(self._pjaxify_template_name(name) for name in template_var)
elif isinstance(template_var, basestring):
template_var = self._pjaxify_template_name(template_var)
return template_var
def _pjaxify_template_name(self, name):
container = self.request.META.get('HTTP_X_PJAX_CONTAINER', False)
if container is not False:
name = _add_suffix(name, clean_container_name(container))
return _add_suffix(name, self.pjax_suffix)
#################################################
# HELPER METHODS #
#################################################
def clean_container_name(name):
return name.replace('#', '')
def _add_suffix(name, suffix):
if "." in name:
file_name, file_extension = os.path.splitext(name)
name = "{0}-{1}{2}".format(file_name, suffix, file_extension)
else:
name += "-{0}".fomat(suffix)
return name
Basically, this mixing renders the default template if the request is not an ajax request. Whereas if the request is AJAX, it renders the pjax_template, if there is one, or the name of the default template prefixed with pjax.

Django best practices - how would you create a page with a form and a list of items the Django-way?

I'm starting with django (and stackoverflow!)
I've been trying to create a webpage with a form and a list of items. ( Django - Mixing ListView and CreateView). I came up with a solution but I'm not convinced by my code!
I'm using Django mixin BaseCreateView and BaseListView to generate the form and list context data. But because it's views, they call directly render_to_response().
So I overloaded the get() method to manually call both parents methods and extract the context data. Then I called render_to_response() myself.
class FormAndListView(BaseCreateView, BaseListView, TemplateResponseMixin):
def get(self, request, *args, **kwargs):
formView = BaseCreateView.get(self, request, *args, **kwargs) # formView contains a response_class
listView = BaseListView.get(self, request, *args, **kwargs) # listView contains a response_class as well...
formData = formView.context_data['form'] # extract the form from the response_class
listData = listView.context_data['object_list'] # extract the object list from the response_class
return render_to_response('textfrompdf/index.html', {'form' : formData, 'all_PDF' : listData},
context_instance=RequestContext(request))
On one hand I'm not re-writing what is already in the mixin to manage forms and lists of items... On the other hand, django is calculating the whole render_to_response() 3 times!
What would be the clean Django-way to write this page?
class FormAndListView(BaseCreateView, BaseListView, TemplateResponseMixin):
def render_to_response(context, **responsekwargs)
return context
def get(self, request, *args, **kwargs):
context = {}
context.update( BaseCreateView.get(self, request, *args, **kwargs) ) # formView contains a response_class
context.update( BaseListView.get(self, request, *args, **kwargs) ) # listView contains a response_class as well...
return TemplateResponseMixin.render_to_response('textfrompdf/index.html', context,
context_instance=RequestContext(request))