Commit dfd53081 authored by Tyler Hallada's avatar Tyler Hallada

Move generating resturaunt grid to JavaScript

Put the last_modified fields from each model to one BaseModel that each
model inherits to keep track of when any part of a schedule changes. Added
an ajax view for getting a JSON form of the schedules for the JavaScript
to use.
parent cc39f03b
......@@ -4,6 +4,7 @@ from website.models import Restaurant, Schedule, OpenTime
class OpenTimeInline(admin.TabularInline):
model = OpenTime
fk_name = 'schedule'
class ScheduleAdmin(admin.ModelAdmin):
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'BaseModel'
db.create_table('website_basemodel', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
))
db.send_create_signal('website', ['BaseModel'])
# Deleting field 'Schedule.last_modified'
db.delete_column('website_schedule', 'last_modified')
# Deleting field 'Schedule.id'
db.delete_column('website_schedule', 'id')
# Adding field 'Schedule.basemodel_ptr'
db.add_column('website_schedule', 'basemodel_ptr',
self.gf('django.db.models.fields.related.OneToOneField')(default=0, to=orm['website.BaseModel'], unique=True, primary_key=True),
keep_default=False)
# Deleting field 'OpenTime.last_modified'
db.delete_column('website_opentime', 'last_modified')
# Deleting field 'OpenTime.id'
db.delete_column('website_opentime', 'id')
# Adding field 'OpenTime.basemodel_ptr'
db.add_column('website_opentime', 'basemodel_ptr',
self.gf('django.db.models.fields.related.OneToOneField')(default=0, to=orm['website.BaseModel'], unique=True, primary_key=True),
keep_default=False)
# Deleting field 'Restaurant.last_modified'
db.delete_column('website_restaurant', 'last_modified')
# Deleting field 'Restaurant.id'
db.delete_column('website_restaurant', 'id')
# Adding field 'Restaurant.basemodel_ptr'
db.add_column('website_restaurant', 'basemodel_ptr',
self.gf('django.db.models.fields.related.OneToOneField')(default=0, to=orm['website.BaseModel'], unique=True, primary_key=True),
keep_default=False)
def backwards(self, orm):
# Deleting model 'BaseModel'
db.delete_table('website_basemodel')
# Adding field 'Schedule.last_modified'
db.add_column('website_schedule', 'last_modified',
self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=datetime.datetime(2013, 1, 30, 0, 0), blank=True),
keep_default=False)
# Adding field 'Schedule.id'
db.add_column('website_schedule', 'id',
self.gf('django.db.models.fields.AutoField')(default=0, primary_key=True),
keep_default=False)
# Deleting field 'Schedule.basemodel_ptr'
db.delete_column('website_schedule', 'basemodel_ptr_id')
# Adding field 'OpenTime.last_modified'
db.add_column('website_opentime', 'last_modified',
self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=datetime.datetime(2013, 1, 30, 0, 0), blank=True),
keep_default=False)
# Adding field 'OpenTime.id'
db.add_column('website_opentime', 'id',
self.gf('django.db.models.fields.AutoField')(default=0, primary_key=True),
keep_default=False)
# Deleting field 'OpenTime.basemodel_ptr'
db.delete_column('website_opentime', 'basemodel_ptr_id')
# Adding field 'Restaurant.last_modified'
db.add_column('website_restaurant', 'last_modified',
self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=datetime.datetime(2013, 1, 30, 0, 0), blank=True),
keep_default=False)
# Adding field 'Restaurant.id'
db.add_column('website_restaurant', 'id',
self.gf('django.db.models.fields.AutoField')(default=0, primary_key=True),
keep_default=False)
# Deleting field 'Restaurant.basemodel_ptr'
db.delete_column('website_restaurant', 'basemodel_ptr_id')
models = {
'website.basemodel': {
'Meta': {'object_name': 'BaseModel'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
},
'website.opentime': {
'Meta': {'object_name': 'OpenTime', '_ormbases': ['website.BaseModel']},
'basemodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['website.BaseModel']", 'unique': 'True', 'primary_key': 'True'}),
'end_day': ('django.db.models.fields.IntegerField', [], {}),
'end_time': ('django.db.models.fields.TimeField', [], {}),
'schedule': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'open_times'", 'to': "orm['website.Schedule']"}),
'start_day': ('django.db.models.fields.IntegerField', [], {}),
'start_time': ('django.db.models.fields.TimeField', [], {})
},
'website.restaurant': {
'Meta': {'object_name': 'Restaurant', '_ormbases': ['website.BaseModel']},
'basemodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['website.BaseModel']", 'unique': 'True', 'primary_key': 'True'}),
'main_schedule': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'restaurant_main'", 'to': "orm['website.Schedule']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'special_schedules': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'restaurant_special'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['website.Schedule']"})
},
'website.schedule': {
'Meta': {'object_name': 'Schedule', '_ormbases': ['website.BaseModel']},
'basemodel_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['website.BaseModel']", 'unique': 'True', 'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'valid_end': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'valid_start': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
}
}
complete_apps = ['website']
\ No newline at end of file
......@@ -2,14 +2,17 @@ from django.db import models
import datetime
class Restaurant(models.Model):
class BaseModel(models.Model):
last_modified = models.DateTimeField('Last Modified', auto_now=True)
class Restaurant(BaseModel):
"""Represents a dining location on campus."""
name = models.CharField(max_length=100)
main_schedule = models.ForeignKey('Schedule',
related_name='restaurant_main')
special_schedules = models.ManyToManyField('Schedule',
related_name='restaurant_special', null=True, blank=True)
last_modified = models.DateTimeField('Last Modified', auto_now=True)
def isOpen(self):
"""
......@@ -35,7 +38,7 @@ class Restaurant(models.Model):
return self.name
class Schedule(models.Model):
class Schedule(BaseModel):
"""
Contains opening and closing times for each day in a week.
......@@ -49,7 +52,6 @@ class Schedule(models.Model):
help_text='Date that this schedule goes into effect')
valid_end = models.DateField('End Date', null=True, blank=True,
help_text='Last day that this schedule is in effect')
last_modified = models.DateTimeField('Last Modified', auto_now=True)
def isOpenNow(self):
"""Return true if this schedule is open right now."""
......@@ -62,14 +64,13 @@ class Schedule(models.Model):
return self.name
class OpenTime(models.Model):
class OpenTime(BaseModel):
"""Represents a period time when a Restaurant is open"""
schedule = models.ForeignKey('Schedule', related_name='open_times')
start_day = models.IntegerField() # 0-6, Monday == 0
start_time = models.TimeField()
end_day = models.IntegerField() # 0-6, Monday == 0
end_time = models.TimeField()
last_modified = models.DateTimeField('Last Modified', auto_now=True)
def isOpenNow(self):
"""Return true if the current time is this OpenTime's range"""
......@@ -102,3 +103,42 @@ class OpenTime(models.Model):
return '%s %s to %s %s' % (weekdays[self.start_day],
self.start_time.strftime("%H:%M:%S"), weekdays[self.end_day],
self.end_time.strftime("%H:%M:%S"))
def export_data():
restaurants = list()
for restaurant in Restaurant.objects.all():
restaurant_data = {'name': restaurant.name}
open_times = list()
for time in restaurant.main_schedule.open_times.all():
open_times.append({
'start_day': time.start_day,
'start_time': time.start_time.isoformat(),
'end_day': time.end_day,
'end_time': time.end_time.isoformat()
})
restaurant_data['main_schedule'] = {
'name': restaurant.main_schedule.name,
'id': restaurant.id,
'open_times': open_times
}
special_schedules = list()
for schedule in restaurant.special_schedules.all():
open_times = list()
for time in schedule.open_times.all():
open_times.append({
'start_day': time.start_day,
'start_time': time.start_time.isoformat(),
'end_day': time.end_day,
'end_time': time.end_time.isoformat()
})
special_schedules.append({
'name': schedule.name,
'id': restaurant.id,
'start': schedule.valid_start.isoformat(),
'end': schedule.valid_end.isoformat(),
'open_times': open_times
})
restaurant_data['special_schedules'] = special_schedules
restaurants.append(restaurant_data)
return restaurants
$.ajax({
url: '/ajax/schedule/',
}).done(function (data) {
$('#grid').append('<div class="row"></div>');
$.each(data.data, function (idx, restaurant) {
if ($('#grid .row').last().children().length < 4) {
$('#grid .row').append(
'<div class="span3 closed" id="' + restaurant.id + '">' + restaurant.name + '</div>'
);
} else {
$('#grid').append('<div class="row"></div>').append(
'<div class="span3 closed" id="' + restaurant.id + '">' + restaurant.name + '</div>'
);
}
var now = new Date();
var schedule = undefined;
$.each(restaurant.special_schedules, function (idx, special) {
if (now >= Date.parse(special.start)
&& now <= Date.parse(special.end)) {
schedule = special;
}
});
if (schedule === undefined) {
schedule = restaurant.main_schedule;
}
$.each(schedule.open_times, function (idx, time) {
if (now >= Date.parse(time.start_time)
&& now <= Date.parse(time.end_time)) {
$('#grid #' + restaurant.id).removeClass('closed');
$('#grid #' + restaurant.id).addClass('open');
}
});
});
});
from django.conf.urls import patterns, url
urlpatterns = patterns('website.views',
url(r'^(?:ajax|api)/schedule/', 'ajax_schedule_data', name='schedule_data'),
url(r'^$', 'restaurant_grid', name='restaurant_grid'),
)
from django.template import RequestContext
from website.models import Restaurant
from website.models import Restaurant, OpenTime, BaseModel, export_data
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.views.decorators.http import condition
import re
import hashlib
import json
def restaurant_grid(request):
......@@ -20,3 +24,18 @@ def restaurant_grid(request):
return render_to_response('restaurant_grid.html', {'restRows': restRows,
'restaurants': restaurants},
context_instance=RequestContext(request))
def gen_etag(request):
return hashlib.sha1(str(OpenTime.objects.all())).hexdigest()
def gen_last_modified(request):
return BaseModel.objects.all().order_by('-last_modified')[0].last_modified
@condition(etag_func=gen_etag, last_modified_func=gen_last_modified)
def ajax_schedule_data(request):
# Wrapping up in an object to avoid possible CSRF attack on top-level
# arrays in JSON objects
return HttpResponse(json.dumps({'data': export_data()}),
content_type="application/json")
......@@ -7,7 +7,9 @@
<link href="{{ STATIC_URL }}css/style.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"></script>
<script type="text/javascript" src="http://www.datejs.com/build/date.js"></script>
<script src="{{ STATIC_URL }}js/bootstrap.min.js"></script>
<script src="{{ STATIC_URL }}js/grid.js"></script>
<link href="{{ STATIC_URL}}img/glyphicons-halflings.png" rel="icons">
<head>
{% block title %}
......
......@@ -3,17 +3,6 @@
{% block content %}
<!-- Generated: {% now "jS F Y H:i" %} -->
<div id="grid">
{% for list in restRows %}
<div class = "row">
{% for restaurant in list %}
<div class = "span3 {% if restaurant.isOpen %}open{% else %}closed{% endif %}">
{{ restaurant.name }}
</div>
{% endfor %}
</div>
{% empty %}
There aren't any restaurants.
{% endfor %}
</div>
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment