Dynamically Display field values in Django template (object.x) - python

I am currently working on an app that uses custom annotate querysets. Currently i have 2 urls setup, but i would need one for each field that the users would like to summarize data for. This could be configured manually, but it would violate DRY! I would basically have +-8 urls that basically do the same thing.
So here is what i did,
I have a created custom model manager
I have a view
I have the URLS configured
All of the above works.
So basically the URL config passes to the view the name of the field to annotate by (group by for SQL folks), the view does some additional processing and runs the custom model manager based on the field that was passed to it.
The URL looks like this:
url('^(?P<field>[\w-]+)/(?P<year>\d{4})/(?P<month>\d+)/(?P<day>\d+)/$','by_subtype', name='chart_link'),
The field is the column in db the that is used when the queryset is actually run. It is passed from the view, to my custom manager. Below is an example of the code from the manager:
return self.filter(start_date_time__year=year).filter(start_date_time__month=month).filter(start_date_time__day=day).values(field).annotate(Count(field))
In addition, i pass the value of field as context variable. This is used to dynamically build the links. However the problem is actually looping through the query set and displaying the data.
So your typical template code looks like this:
{% for object in object_list %}
{{ object.sub_type }} : {{ object.sub_type__count|intcomma }}
{% endfor %}
Basically you have to hard code the field to diplay (i.e object.x), is there anyway to dynamically assign this? i.e
if field = business
then in the template it should automatically process:
{{ object.business }}
Can this be done? Or would i need to create several URLS? Or is there a better way to achieve the same result, a single view and url handling queries dynamically.
You can find the code over at github, the template part is now working using this snippet: http://www.djangosnippets.org/snippets/1412/ So if you come across this later and want to do something similar have a look at the code snippet at github. : http://gist.github.com/233262

It sounds like you want to do something along the lines of:
# in the views.py:
field = 'business'
{# in the template: #}
{{ object.field }}
and have the value of object.business appear in the output. This isn't possible with the Django template language out of the box.
There are snippets that define template filters you can use to accomplish this though: http://www.djangosnippets.org/snippets/1412/

As mentioned above, you can do this with a custom template filter.
For example:
#register.filter(name='get_attr')
def get_attr(obj, field_name):
if isinstance(obj, dict):
return obj.get(field_name)
return getattr(obj, field_name)
Then, using it in your template:
{{ obj|get_attr:'business' }}

Related

Calling a route from a template

Can I have a route that renders a template that I can use in another template?
I imagine something like
#app.route('/tags/')
def tags():
return render_template('tags.html', tags=create_tags())
and then somehow invoke the route from a different template.
<h2>Tags</h2>
{{ render('/tags/') }}
Routes don't render templates, functions do. All the route does is point a url to a function. So, the obvious solution to me is to have a function that returns the rendered tag template:
def render_tags_template():
return render_template('tags.html', tags=create_tags())
Then we want to associate the function with the url "/tags"
app.add_url_rule('/tags', endpoint='tags', view_func=render_tags_template)
We also want to be able to access this function from within our templates. Accessing it via the url through another request would most likely be a job for ajax. So we have to get render_tags_template into the template context.
render_template('some_random_template.html', render_tags_template=render_tags_template
then in your some_random_template.html:
{{render_tags_template()}}
if you don't want to pass render_tags_template explicitly, you can add it as a template global:
app.jinja_env.globals['render_tags_template'] = render_tags_template
and use it freely in all of your templates, without having to pass it explicitly.
Depending on what your actually trying to do, simply including tags.html may be the best and easiest solution. Using a function to generate the content gives you a bit more control and flexibility.
You can include the tags.html template in your template.
{% include "tags.html" %}
You have to pass the tags to your template, but this is the way to do it.

how to render a Queryset into a table template-django

I have a model which is defined as shown which is acted upon a query and gets a list of objects that have to placed in appropriate cells of a table. Here is the relevant part of the code.
class Location(models.Model):
x=models.IntegerField(null=True)
y=models.IntegerField(null=True)
z=models.CharField(max_length=5,null=True)
def __unicode__(self):
return self.z
From this db i want retrieve all the objects and place them in a 2d-table with row and column defined by x,y of that object.If there is no object for certain (x,y) then that particular slot should be shown empty in the table.This is the view I wrote to meet those ends.
def gettable(request):
events=[]
for xdim in xrange(3):
xe=[]
for ydim in xrange(3):
object=[0]
object.append(Location.objects.filter(x=xdim,y=ydim))
xe.append(object[-1])
events.append(xe)
return render(request, 'scheduler/table.html', {'events':events})
Here is the html part of the code
<table border="1">
<th>Header 0</th>
<th>Header 1</th>
<th>Header 2</th>
{% for event in events %}
<tr>
{% for x in event %} <td>{{ x }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
I have to tackle multiple issues here.
1.My code for views is not at all elegant (which is bad since I know django offers lots of stuff to tackle such tasks) as I am defining variables specifically to loop through instead of taking those from the (x,y) values of database objects.
2.I get output in [<Location: 21>] format but I want it as '21'.
3.How do I introduce empty cells where there doesnot exist any object for given (x,y).
4.Please suggest any other way possible which can make my code simpler and general.
If you want to make your code simpler, I would like to recommend to use application django-tables2. This approach can solve all your issues about generating tables.
As the documentation says:
django-tables2 simplifies the task of turning sets of data into HTML
tables. It has native support for pagination and sorting. It does for
HTML tables what django.forms does for HTML forms. e.g.
Its features include:
Any iterable can be a data-source, but special support for Django querysets is included.
The builtin UI does not rely on JavaScript.
Support for automatic table generation based on a Django model.
Supports custom column functionality via subclassing.
Pagination.
Column based table sorting.
Template tag to enable trivial rendering to HTML.
Generic view mixin for use in Django 1.3.
Creating a table is as simple as:
import django_tables2 as tables
class SimpleTable(tables.Table):
class Meta:
model = Simple
This would then be used in a view:
def simple_list(request):
queryset = Simple.objects.all()
table = SimpleTable(queryset)
return render_to_response("simple_list.html", {"table": table},
context_instance=RequestContext(request))
And finally in the template:
{% load django_tables2 %}
{% render_table table %}
This example shows
one of the simplest cases, but django-tables2 can do a lot more! Check
out the documentation for more details.
It is also possible to use a dictionary instead of a queryset.
Per point:
IMO you can get away with creating a custom filter or a tag and using the queryset.
You need to define a __unicode__ (or __string__) method to return your desired item.
If the value is empty or the item doesn't exist, the rendered result will be empty too.
HTH
For point 2, you're giving each cell a list rather than a single object, {{ x.0 }} should give you the right value, but it also suggests you're approaching it wrong in your view logic.

Django: avoiding multiple evaluations of the same expression in a template?

When passing an object called widget as part of the context to rendering a django template, I may have a method which is a bit expensive, but I want to display the result of it more than once.
Python:
class Widget:
def work(self):
# Do something expensive
Template
This is a widget, the result of whose work is {{widget.work}}. Do
you want to save {{widget.work}} or discard {{widget.work}}?
Clearly I could work around this by evaluating the method once in the view code, and then passing the result in, but this seems to couple the view and the template too much. Is there a way for the template author to stash values for re-use later in the template? I would like to do something like this:
{% work_result = widget.work %}
This is a widget, the result of whose
work is {{work_result}}. Do you want to save {{work_result}} or discard {{work_result}}?
Does such a construct exist in the django template language?
{% with %}
{% with work_result=widget.work %}
Look Django docs for more information

Additional fields in Django admin interface

Suppose I have some persistent model property that's not backed up by a model field, how do I allow editing this field in the admin interface?
Example setup:
# models.py
# appropriate imports...
class MyModel(Model):
# regular fields.
foo = CharField(max_length=50)
bar = BooleanField()
# ...
# custom property, backed by a file.
def _get_meh ( self ):
return ... # read from file
def _set_meh ( self, value ):
... # write to file.
meh = property(_get_meh, _set_meh)
meh's value is actually stored in a file on disk who's path depends on the value in foo. I'd like to be able to edit meh's value from the admin interface.
# admin.py
# appropriate imports...
class MyModelAdmin(ModelAdmin):
# what do I put here?
Note: in case someone needs to ask, I'm using Django version 1.2.1, but upgrading is possible if that is required by your solution. Anything that runs on Python 2.5 will do, this I can't really upgrade for the moment.
Take a look at this:
http://www.scribd.com/doc/68396387/Adding-extra-fields-to-a-model-form-in-Django%E2%80%99s-admin-%E2%80%93-Hindsight-Labs
(this one went offline, http://www.hindsightlabs.com/blog/2010/02/11/adding-extra-fields-to-a-model-form-in-djangos-admin/)
Basically, you'll create a MyModelFrom subclassed from forms.ModelForm and:
Add the extra meh fields to the MyModelFrom definition.
Override the constructor of the MyModelFrom, set the self.initial meh property if a model instance was passed to the form.
Override the save method of the MyModelFrom, set the meh property on the model instance based on the form fields.
This way, the meh property would be correctly filled at your Model, but you'll also need to override MyModel's save() method to actually persist this value to your disk file:
(Google for "django model override save", sry, it seems I can't post more than a link per answer till I get more than 10 rep...)
Cheers,
Ny Django knowledge isn't that great, but depending on how complicated you want it to be, I'm not sure something like this can be easily done without much hackery.
Anyhow, if you want to add it to Add MyModel page, you can edit the appropriate admin template.
So in your template directory, create something like:
admin/app_label/MyModel/change_form.html
Then extend the base template, and add your own content:
{% extends "admin/change_form.html" %}
{% block something_you_want_to_override %}
<p>Your HTML goes here</p>
{% endblock %}
Is there really no way you can get this custom field into an actual Django field though? Surely you can override the save() method on the model and do it that way? Or use a pre_save signal?
Cheers,
Victor

Django ManyToMany Template rendering and performance issues

I've got a django model that contains a manytomany relationship, of the type,
class MyModel(models.Model):
name = ..
refby = models.ManyToManyField(MyModel2)
..
class MyModel2(..):
name = ..
date = ..
I need to render it in my template such that I am able to render all the mymodel2 objects that refer to mymodel. Currently, I do something like the following,
{% for i in mymodel_obj_list %}
{{i.name}}
{% for m in i.refby.all|dictsortreversed:"date"|slice:"3" %}
{{.. }}
{% endfor %}
<div> <!--This div toggles hidden/visible, shows next 12-->
{% for n in i.refby.all|dictsortreversed:"date"|slice:"3:15" %}
{{.. }}
{% endfor %}
</div>
{% endfor %}
As the code suggests, I only want to show the latest 3 mymodel2 objects, sorted in reverse order by date, although the next 12 do get loaded.
Is this a very inefficient method of doing so? (Given that results for the refby.all could be a few 100s, and the total no of results in "mymodel_obj_list" is also in 100s - I use a paginator there).
In which case, whats the best method to pre-compute these refby's and render them to the template? Should I do the sorting and computation in the view, and then pass it? I wasn't sure how to do this in order to maintain my pagination.
View code looks something like,
obj_list = Table.objects.filter(..) # Few 100 records
pl = CustomPaginatorClass(obj_list...)
And I pass the pl to the page as mymodel_obj_list.
Thanks!
I assume mymodel_obj_list is a QuerySet. You're accessing a foreign key field inside the loop, which means, by default, Django will look up each object's refby one at a time, when you access it. If you're displaying a lot of rows, this is extremely slow.
Call select_related on the QuerySet, to pull in all of these foreign key fields in advance.
https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related
Should I do the sorting and
computation in the view, and then pass
it?
Yes, definitely.
It is not really a matter of performance (as Django's querysets are lazily evaluated, I suspect the final performance could be very similar in both cases) but of code organization.
Templates should not contain any business logic, only presentation. Of course, sometimes this model breaks down, but in general you should try as much as possible to keep into that direction.

Categories

Resources