Django: Grouping by Dates and Servers - sql

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.

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.

Macro to surface models to other schemas - dbt_utils.star()

Problem
Currently in my CI process, I am surfacing specific models built to multiple schemas. This is generally my current process.
macros/surface_models.sql
{% set model_views = [] %}
{% for node in graph.nodes.values() %}
{% if some type of filtering criteria %}
{%- do model_tables.append( graph.node.alias ) -%}
{% endif %}
{% endfor %}
{% for view in model_views %}
{% set query %}
'create view my_other_schema.' ~ table ~ 'as (select * from initial_schema.' ~ table ~ ');'
{% endset %}
{{ run_query(query) }}
{% endfor %}
while this works, if the underlying table/view's definition changes, the view created from the above macro will return an error like: QUERY EXPECTED X COLUMNS BUT GOT Y
I could fix this by writing each query with each query's explicit names:
select id, updated_at from table
not
select * from table
Question
Is there a way to utilize the above macro concept but using {{ dbt_utils.star() }} instead of *?

CS50 Finance History Problem with SQL SELECT

I don't understand why I can't SELECT the 'transaction' column from my TABLE portfolio. I created a TABLE using the syntax below:
CREATE TABLE 'portfolio' ('transaction' integer primary key autoincrement,
'datetime' datetime, user_id bigint, 'symbol' varchar(5), 'price' numeric(8,
2), 'shares' integer, 'total' numeric(8, 2));
The transaction keeps a running count of buy/sell orders. When I have transaction in the SELECT statement, it gives me an error, see below:
RuntimeError: near "transaction": syntax error [SQL: 'SELECT transaction,
datetime, symbol, shares, price FROM portfolio WHERE user_id = 2']
(Background on this error at: http://sqlalche.me/e/e3q8)
If I don't include transaction in the python code, then everything works and the table is displayed on the webpage. What is preventing me from selecting transaction? In the code, I included transaction.
#app.route("/history")
#login_required
def history():
"""Show history of transactions"""
#create table
history = db.execute("SELECT transaction, datetime, symbol, shares, price FROM portfolio WHERE user_id = :user_id", user_id = session["user_id"])
history_info = []
for info in history:
transaction = info["transaction"]
datetime = info["datetime"]
symbol = info["symbol"]
shares = info["shares"]
price = info["price"]
total = abs(shares * price)
history_info.append({"transaction":transaction, "datetime":datetime, "symbol":symbol, "shares":shares, "price":price, "total":total})
return render_template("history.html", history_info = history_info)
The html below is what will be displayed on the webpage. Currently, I left off the transaction.
{% extends "layout.html" %}
{% block title %}
History
{% endblock %}
{% block main %}
<table class="table table-bordered">
<thead>
<th>Purchase Date/Time</th>
<th>Symbol</th>
<th>Shares</th>
<th>Price</th>
<th>Total</th>
</thead>
<tbody>
{% for stock in history_info %}
<tr>
<td>{{ stock.datetime }}</td>
<td>{{ stock.symbol }}</td>
<td>{{ stock.shares }}</td>
<td>{{ stock.price }}</td>
<td>{{ stock.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
Resolved....
transaction is a reserved word.
Try putting it in brackets [transaction] and see if that works for you.

Twig: Finding the sum of values of rows in column

How do I find the total value of all the rows in a column with Twig? For example I have a column "QTY" that will list number of quantities of each row, I want the sum of the total ROWS of QTY (not the sum of qty). What is the tag/logic in Twig?
I have something like this:
<table class="tablesorter">
<thead>
<th>DA</th>
<th>Part</th>
<th>Batch</th>
<th>Qty</th>
</thead>
{% for getbatches in getbatch %}
<tr>
<td>{{getbatch.dano}}</td>
<td>{{getbatch.partno}}</td>
<td class="highlight">{{getbatch.batchno}}</td>
<td>{{getbatch.inqty}}</td>
</tr>
{% endfor %}
</table>
For the rows that populate, I would like the count of the column of QTY, or any column.
Base on your code and according to that you want to get Count of rows in Qty column you can try
<table class="tablesorter">
<thead>
<th>DA</th>
<th>Part</th>
<th>Batch</th>
<th>Qty</th>
</thead>
{% set row_count = 0 %}
{% for getbatches in getbatch %}
<tr>
<td>{{getbatch.dano}}</td>
<td>{{getbatch.partno}}</td>
<td class="highlight">{{getbatch.batchno}}</td>
<td>{{getbatch.inqty}}</td>
</tr>
{% set row_count = row_count + 1 %}
{% endfor %}
</table>
if you want to show that amount somewhere (like a span) you can use <span>{{ row_count }}</span> after
UPDATED
A better solution to show the rows count anywhere if your twig template might be just showing the count of getbatches:
<span>Row count: </span><span>{{ getbatches is defined ? getbatches|length : 0 }}</span>
If you print rows of a table in twig and wany to get the "count of rows in QTY column", you should pass this data to twig from doing a simple count() on the array of rows. If you want to do it "the hard way", you could do:
{% set numRows = 0 %}
{% for .... %}
{% set numRows = numRows + 1 %}
{% endfor %}
but as #TheLittlePig said, twig's purpose is to display data, not do calculations

Django template tag for Model query result

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 %}