Generic list view + site-wide data in django? - python

I have a view that perfectly fits the ListView in Django. Like this:
url(r'^$',
ListView.as_view(
queryset=Poll.objects.order_by('-pub_date')[:5],
context_object_name='latest_poll_list',
template_name='polls/views/index.html')),
However I on the page of the view I also would like to display content from another model. This model contains only one row of data. It's sitewide and contains the footer-text page-title etc.
What's the best solution for this? Ideally I'd like to keep the generic-model approach.

There are several methods that will solve this issue. The view is definitely not the correct place.
Template Tags
One way to use template tags is as mini-views. Whether you are requesting data from another model, or rendering an included template.
Because you can also pass parameters into the template tag, they can be customized by the context.
Context Processors
For simpler information,context processors work well. I wouldn't get too complicated with the data, as it is global and can slow down every request.
On an aside, I would also question your one-row model. My guess is that this is to allow user editing. If users access it, expect every possible way of screwing it up. For example, adding more rows. There are several Django applications for managing user-editable settings that might be useful. If the data isn't going to change often, I would make it an actual setting, or put it in a template snippet and {% include %} it.

Related

Too many templates in Django

I am learning Django and I programming a CRUD for various objects. Currently I need to generate three templates per object: one for creation, one for update and one for a list. Look at how many templates I got in the picture.
The process is becoming painful.
What I am doing wrong and how to correct it?
Thanks.
From your comment:
The problem is that If I need to make a change, for example, add a new button, I have to make it in all the templates.
That sounds wrong. Either a button belong to one type of thing and then it should only exist in that template, or it should be on every page and then it should be in the base template.
You can make one template with your basic page layout (including such buttons), and have "blocks" in them that are then filled out by each template that extends the base template.
See the Django documentation about template inheritance.
Also, I think that in most cases the "create" and "update" pages are going to be extremely similar; usually they use the same template, one with data already filled in, the other without.
You could have a base template, then a generic list template and a generic edit/create template, with templates for each type of thing extending the list and the edit templates to fill in only the relevant fields.
Also, maybe you use HTML that is close enough to what the Django forms can render themselves. Then as long as you call the edit/create form the same in each of your views (like "form"), the template can just render the form and they can all use the same template.
If you're building a big web-app then this is normal for templates to be more.
Heavy (big) web-app means = more templates + more code + more time + more features

Implementing Universal Search in a Django Application

We have a large Django application made up of a large number of different views (some of which contain forms). As with most large applications, we use a base layout template that contains the common layout elements across the applications (mainly a header and a footer), which the templates for all of our views extend.
What we are looking to do is create a universal search box in our application, accessible on every page, which allows users to perform searches across the entire application, and want to place the search box inside the header, which involves placing a form inside our base layout template. This means that every view in our application will need to be able to handle the submission of this search form. Once this search form is submitted, we will need to redirect the user to another view containing the search results.
However, we are struggling to come up with a pattern to handle this. Does anyone know of functionality built into Django that will help us to build this? Failing that, can anyone suggest a good strategy for modifying our application so that we can handle this use-case without having to modify a large number of existing views (which we don't have the resources to do at the moment)?
Please note that the focus of this question is intended to be the best way to handle the submission of a form which appears in every view, and not strategies for implementing a universal search algorithm (which we have already figured out).
Ideas Explored So Far
Our first idea was to create a base View class that implements handling the universal search form submission, and have each of our views extend this. However, this is not possible because we already have views that inherit from a number of different Django view classes (TemplateView, ListView, FormView and DeleteView being some examples), and to be able to build our own common view class would mean either writing our own version of these Django view classes to inherit from our own view base class, or re-writing a large number of our views so they don't use the Django view classes.
Our next idea was to implement a mixin that would handle the universal search form submission, in an attempt to add this functionality to all our views in a way that allows us to continue using the different Django view classes. However, this brought to light two new problems: (a) how could we do this without modifying each of our views to become a form view, and (b) how can we do this in a way that allows the form handling logic to play nicely when mixed in to existing FormViews?
This seems like such an obvious question that maybe I'm overlooking something. But as others have said your universal search form should not make a POST request to the view that rendered the current page.
Each html form has an action attribute. The attribute of your search form should point towards an URL. Probably something like /search. That url would have a view behind it that handled the POST request from the form and returned the search results. Django has URL template tags to make this easy. {% url 'myapp.views.search' %} will give you the correct url for the search view function if it lived inside the views module in myapp. So the relevant bit of html in your base template would be something like:
<form action="{% url 'myapp.views.search' %}">
<input type="text" name="qs" placeholder="Search">
</form>
If you are planning on displaying the search results on a new page there is absolutely no need to return JSON or anything like that. Just have a search view that looks like this
def search(request):
query = request.POST.get('qs', '')
results = SomeModel.objects.filter(name=query) # Your search algo goes here
return render(request, 'search_results.html', dict(results=results))
Instead of handling the form submission on every view of the application, you can implement a separate view (endpoint), which handles all the search queries. (an endpoint which returns JSON result) since you dont want to add overhead of rendering the whole page with that view. So the search query (which client side AJAX performs to the webserver) will return JSON response, and the Javascript can render that response. This way you can keep the search view isolated from the rest of the views. (Django REST will be helpful in this case)
And this search form will be included in your base template, so your search box is accessible from the entire application, and it submits to the same view. And the AJAX function will handle the server response for rendering it.
It seems like you just need to create another SearchView which takes the query and displays the results. I am not sure if the results have to be displayed differently depending on which page the search has been performed from but it does not seem like.
The form would not have anything to do with the other views. You could just hard code it in the base template.

Dynamically includes with query

I have a footer included in my base template with:
{% include "footer.html %}
I need to show it in every page. But the footer has several statics which needs to be calculated with several queries each time the page loads.
As far as I know, this include cannot run queries because any views is called. And I don't want to replicate the query for that in all my views, I think it's a dirty solution.
What's the best practice in this case? I think it's a quite common problem.
Although context processors are good for including standard things in every template, I suspect for your purposes a custom template tag that renders the entire footer would be a better bet - probably an inclusion tag would do the job.
If statistics are global (not something related to specific page/request) you can implement your custom context processor which can calculate statistics and add corresponding variables in the context. That context variables/dict can be used by footer.html to put the statistics.
Refer Writing custom context processor
You can use context processors to run your queries in all views and update your context with necessary data.
What about creating a Context Processor, and return the query from there ?
The result will be available in every view, if that's what you desire ?
You should write context processor to work this out :
writing context processors
Another option not mentioned here so far are custom template tags. Depending on what exactly you want to do a context processor might be overkill.

Is there a way to have something execute for every view in django?

I'm new to Django and coming from Rails, so that may explain my odd questions below:
I have a main layout that has a sidebar that lists the latest updates to the site. That main layout is used for every page in my webapp so every template that is created extends main.html.
For the latest updates section, I just want to get the last 5 updates from posts to the web app every time a page is rendered. I thought about making the sidebar do this through an ajax call once the page is loaded, but I thought this may not be my best option.
I also considered creating a tag to do this for me and then just calling the tag inside of main.html. This is simple enough, but I'd have to write a lot of HTML inside of the tag code, which seems to be a little annoying (a lot of string appending and such, unless I'm wrong and there is a better way?)
I have read about Context Processors. This seemed to be exactly what I wanted, but it appears this may cause another issue where I have to pass a context_instance to every single render_to_response? This appears to be a lot of code repeat and I'm trying to avoid that if possible. Is there a way to just make render_to_response always take the RequestContext object without always having to specify it?
Are there any other ways to achieve having some code run for every view and eliminate the need to always pass data to a view?
Django 1.3 added the render shortcut which is the same as render_to_response but with RequestContext automatically used.
Templates is a appropriate place for this: the variant with custom tag and template inheritance is simple and convenient. To avoid string appending use mini-template just for your tag: it is called inclusion tags.
I would definitely go for the Ajax call, it is as simple as to create an small view which queries the model for the 5 latest posts, serializes them into json or xml data, and returns them in your HttpRequest object.
You can use direct_to_template instead of render_to_response.

Django boilerplate template code

I am a django newbie and in creating my first project I have come to realize that a lot of my boilerplate code (the lists on the side of my page). I have to recreate them in every view and I am trying to stick with DRY but I find myself rewriting the code every time. Is there a way to inherit from my base views and just modify a few objects?
Thanks,
James
Yes, you'll want to look into template inheritance, which lets you share common elements between templates, and the {% include %} template tag, which lets you create reusable template "snippets" that can be included in other templates.
Edit: Re-reading the question, it sounds like you're talking about boilerplate code that you have in your view functions/methods that you're using to generate context shared by multiple templates. In that case, mipadi's answer is the right one: Look into context processors.
You might want to use a context processor for this work.
For the lists of recent articles etc, custom template tags are the thing you need. Whereas a context processor will populate your context with the lists automatically, a template tag can actually do that plus create the whole HTML markup for the column itself.
For large blocks of static html that reappear consistently you can use the include template tag:
{% include 'static/some_file.html' %}
The includes are stored in your template file system, just like templates.
If you don't decide to use context processor for some reasons (this solution looks reasonable here) you can always encapsulate some common logic into util functions and use them in your views.
You can also take a look at Generic views - this is a good way to 'stay DRY' with your code

Categories

Resources