Django template tag for Model query result - django-templates

I wonna simple tag, for showing table of any model arrays like:
{% table city_list %}
Do anybody see such things?

You can try django-tables app, which allows you to do the following, given model Book:
# Define
class BookTable(tables.ModelTable):
id = tables.Column(sortable=False, visible=False)
book_name = tables.Column(name='title')
author = tables.Column(data='author__name')
class Meta:
model = Book
# In your views
initial_queryset = Book.objects.all()
books = BookTable(initial_queryset)
return render_to_response('table.html', {'table': books})
# In your template table.html
<table>
<!-- Table header -->
<tr>
{% for column in table.columns %}
<th>{{ column }}</th>
{% endfor %}
</tr>
<!-- Table rows -->
{% for row in table.rows %}
<tr>
{% for value in row %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
I think the above is much more elegant and self explanatory than just doing
{% table book_list %}

Try generic vieww e.g. http://www.djangobook.com/en/2.0/chapter11/

I've made a fork of django-tables which makes this extremely easy. Here's a simple example:
In models.py:
from django.db import models
class City(models.Model):
name = models.CharField(max_length=200)
state = models.CharField(max_length=200)
country = models.CharField(max_length=200)
In tables.py:
import django_tables as tables
from .models import City
class CityTable(tables.Table):
class Meta:
model = City
In views.py:
from django.shortcuts import render_to_response
from django.template import RequestContext
from .models import City
from .tables import CityTable
def city_list(request):
queryset = City.objects.all()
table = CityTable(queryset)
return render_to_response("city_list.html", {"city_table": table},
context_instance=RequestContext(request))
In city_list.html:
{% load django_tables %}
{% render_table city_table %}

Related

Obtaining an item count from a list in a Django template

I am trying to get the object count on a 'list' using the length filter in the Django template and it is returning the number of characters. It looks like my list is not a real list but rather a long string. My mixin looks like this:
class ItemObjectMixin:
model = None
template_name = None
my_filter = ItemFilter
def get(self, request):
items = self.model.objects.all()
items_count = items.count()
itemsFilter = ItemsFilter(request.GET, queryset=items)
items = itemsFilter.qs
remaining = items.count()
return render(request, self.template_name, locals())
And my class-based view looks like:
class MyItemsListView(ItemObjectMixin, ListView):
model = Items
template_name = "Items/myItems.html"
My template has the following partial code:
<tbody>
{% for item in items %}
<tr>
<td>{{ item.title }}</td>
<td>{{ item.id }}</td>
{% if item.group_of_items %}
<td>{{ item.group_of_items|length }}</td>
{% endif %}
<td>{{ item.group_of_items }}</td>
</tr>
{% endif %}
</tbody>
The code {{ item.group_of_items|length }} gives the number of characters for each instance of 'group_of_items'. I understand why this is happening but would like a solution where the for loop gives a list of objects rather than a string. Any takers? Cheers.

How to dsiplay value from another model based on the same if form another model in django

I have db and the following classes:
in models.py
class Student(models.Model):
name=models.CharField(max_length=200)
surname=models.CharField(max_length=500)
class Class101(models.Model):
name=models.CharField(max_length=200)
math=models.DecimalField(max_length=200)
english=models.DecimalField(max_length=200)
in views.py
total_grade=Class101.objects.filter(Q(math__gt=70) & Q(english__gt=58))
context ={'tg':total_grade}
in template.html
{% for grade in tg %}
<p> {{grade.name}} </p>
{% endfor %}
it lists name of students however i want to put in the template :
{{grade.name}} - {{grade.surname}}
{{grade.surname}} where surname is from model Student
This code does not display surname but only name as the name in the class Class101 . How to make to display surname from another model where both models have the same name?
In that case, you should have ForeignKey relation between Class101 and Student model like this:
class Student(models.Model):
name=models.CharField(max_length=200)
surname=models.CharField(max_length=500)
class Class(models.Model):
code = models.CharField(max_length=100)
student=models.ForeignKey(Student, on_delete=models.CASCADE)
math=models.DecimalField(max_length=200)
english=models.DecimalField(max_length=200)
Then you could use Student value in template:
{% for grade in tg %}
<p> {{grade.student.name}} - {{grade.student.surename}} </p>
{% endfor %}

Flask-Admin - Inline Model not working with field named something other than 'id'

I am looking at inline models and have been testing out the example here:
https://github.com/mrjoes/flask-admin/tree/master/examples/sqla-inline
I have noticed that if the primary key field of the LocationImage model/table is renamed to something other than ID, then the after_delete handler does not get triggered.
So this works
class LocationImage(db.Model):
id = db.Column(db.Integer, primary_key=True)
alt = db.Column(db.Unicode(128))
path = db.Column(db.String(64))
location_id = db.Column(db.Integer, db.ForeignKey(Location.id))
location = db.relation(Location, backref='images')
#event.listens_for(LocationImage, 'after_delete')
def _handle_image_delete(mapper, conn, target):
try:
if target.path:
os.remove(op.join(base_path, target.path))
except:
pass
But if I rename the id column like so,
image_id = db.Column(db.Integer, primary_key=True)
Then _handle_image_delete does not get called.
I cannot fathom where this field is specified and how to make it work with a PK named something other than 'id'.
Thank you
In field_list.html a hidden field is rendered for the primary key. You need to change it to output your renamed field {{ field.form.image_id }}.
{% import 'admin/model/inline_list_base.html' as base with context %}
{% macro render_field(field) %}
{% set model = field.object_data %}
{% if model and model.path %}
{{ field.form.image_id }}
<img src="{{ url_for('static', filename=model.path) }}" style="max-width: 300px;"></img>
{% else %}
{{ field }}
{% endif %}
{% endmacro %}
{{ base.render_inline_fields(field, template, render_field) }}

How access tuple item

models.py
class MyModel(models.Model):
GENDER = (('M',"Male"),('F',"Female"))
gender = models.CharField(max_length = 1, choices = GENDER)
template.html
{% for item in mymodels %}
{{ item.GENDER[item.gender] }} #HOW TODO?
{% endfor %}
You can find some answers here
I think that best bet is to use helper function that returns proper value or extend/write new filter.

Django: Grouping by Dates and Servers

So I am trying to emulate google app's status page: http://www.google.com/appsstatus#hl=en but for backups for our own servers. Instead of service names on the left it'll be server names but the dates and hopefully the pagination will be there too. My models look incredibly similar to this:
from django.db import models
STATUS_CHOICES = (
('UN', 'Unknown'),
('NI', 'No Issue'),
('IS', 'Issue'),
('NR', 'Not Running'),
)
class Server(models.Model):
name = models.CharField(max_length=32)
def __unicode__(self):
return self.name
class Backup(models.Model):
server = models.ForeignKey(Server)
created = models.DateField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=2, choices=STATUS_CHOICES, default='UN')
issue = models.TextField(blank=True)
def __unicode__(self):
return u'%s: %s' % (self.server, self.get_status_display())
My issue is that I am having a hell of a time displaying the information I need. Everyday a little after midnight a cron job will run and add a row for each server for that day, defaulting on status unknown (UN).
My backups.html:
{% extends "base.html" %}
{% block content %}
<table>
<tr>
<th>Name</th>
{% for server in servers %}
<th>{{ created }}</th>
</tr>
<tr>
<td>{{ server.name }}</td>
{% for backup in server.backup_set.all %}
<td>{{ backup.get_status_display }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{% endblock content %}
This actually works but I do not know how to get the dates to show. Obviously {{ created }} doesn't do anything but the servers don't have create dates. Backups do and because it's a cron job there should only be X number of rows with any particular date (depending on how many servers we are following for that day).
Summary
I want to create a table, X being server names, Y being dates starting at today while all the cells being the status of a backup. The above model and template should hopefully give you an idea what my thought process but I am willing to alter anything. Basically I am create a fancy excel spreadsheet.
I suggest adding a function to get the dates you want to show, that's independent of a Server instance. Then you can use it both to get the recent backups and to get the dates for the header. In models.py:
from django.db import models
import datetime
def recent_dates():
return [datetime.date.today() - datetime.timedelta(days=days)
for days in range(-6, 1)]
class Server(models.Model):
...
def backup_for_date(self, date):
next_date = date + datetime.timedelta(days=1)
return self.backup_set.get(created__gte=date, created__lt=next_date)
def recent_backups(self):
return [self.backup_for_date(date) for date in recent_dates()]
Then, if you use the function in views.py:
from django.shortcuts import render_to_response
from myapp.models import Server, recent_dates
def status(request):
servers = Server.objects.all()
return render_to_response('status.html',
{'dates': recent_dates(), 'servers': servers}
)
...you can use the recent_dates variable to print the headers in the template:
{% extends "base.html" %}
{% block content %}
<table>
<tr>
<th>Name</th>
{% for date in recent_dates %}
<th>{{ date }}</th>
{% endfor %}
</tr>
{% for server in servers %}
<tr>
<td>{{ server.name }}</td>
{% for backup in server.recent_backups() %}
<td>{{ backup.get_status_display }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{% endblock content %}
Using this method also makes sure the cells don't get shifted out of position if data is missing. The code I provided will raise an exception in the call to the get() method inside backup_for_date() if data is missing, but backup_for_date() could easily be modified to return None in that case.