From 39d2613b75160a47a93df560d51b30854249ce9d Mon Sep 17 00:00:00 2001 From: bnewbold Date: Thu, 12 Jul 2007 00:59:01 -0400 Subject: almost working again --- equations/models.py | 119 ++++++++++++++++++++- equations/signals.py | 65 +++++++++++ equations/templates/equations/equation_detail.html | 27 +++++ equations/templates/equations/equation_list.html | 24 +++++ equations/views.py | 31 +++++- settings.py.example | 87 +++++++++++++++ templates/base.html | 2 +- templates/go.html | 6 +- urls.py | 31 +++++- 9 files changed, 381 insertions(+), 11 deletions(-) create mode 100644 equations/signals.py create mode 100644 equations/templates/equations/equation_detail.html create mode 100644 equations/templates/equations/equation_list.html create mode 100644 settings.py.example diff --git a/equations/models.py b/equations/models.py index 71a8362..6791eb2 100644 --- a/equations/models.py +++ b/equations/models.py @@ -1,3 +1,120 @@ from django.db import models +from django.utils.translation import gettext_lazy as _ +import django.contrib.auth.models as auth +from django.conf import settings +from django.dispatch import dispatcher +from django.db.models import signals +from signals import update_render -# Create your models here. +class Symbol(models.Model): + name = models.CharField(_("Name"), maxlength=256) + latex = models.TextField(_("Raw LaTeX"), unique=True) + unicode = models.TextField(_("Unicode Representation"), blank=True) + renderdir = "symbolrenders/" + render = models.ImageField(_("Rendered Image"), + upload_to=renderdir, editable=False) + + class Meta: + get_latest_by = 'name' + class Admin: + ordering = ['name'] + + def __str__(self): + return self.name + def get_absolute_url(self): + return "/symbol/%s/" % self.id + def get_admin_url(self): + return "/admin/symbols/%s/" % self.id + #def save(self): + # super(Symbol, self) + # self.update_generic_variable() + def save(self): + super(Symbol, self).save() + self.render = self.renderdir + "%s.png" % self.id + super(Symbol, self).save() + +def update_generic_variable(sender, instance, signal, *args, **kwargs): + """Checks if there is a generic variable associated with this + symbol; create one if there isn't""" + for v in Variable.objects.filter(isgeneric=True): + if v.latex == instance.latex: + return + genericv = Variable(name="Generic %s" % instance.name, + latex=instance.latex, + unicode=instance.unicode, + symbol=instance, + isgeneric=True) + genericv.save() + +dispatcher.connect(update_render, signal=signals.pre_save, sender=Symbol) +dispatcher.connect(update_generic_variable, signal=signals.post_save, + sender=Symbol) + +class Variable(models.Model): + name = models.CharField(_("Name"), maxlength=256) + latex = models.TextField(_("Raw LaTeX"), unique=True) + unicode = models.TextField(_("Unicode Representation"), blank=True) + description = models.TextField(_("Description"), blank=True) + renderdir = "variablerenders/" + render = models.ImageField(_("Rendered Image"), + upload_to=renderdir, editable=False) + reference = models.URLField(_("Reference URL"), blank=True) + symbol = models.ForeignKey(Symbol, verbose_name=_("Symbol")) + isgeneric = models.BooleanField(_("Is Generic?"), default=False) + + class Meta: + get_latest_by = 'name' + class Admin: + ordering = ['name'] + + def __str__(self): + return self.name + def get_absolute_url(self): + return "/variable/%s/" % self.id + def get_admin_url(self): + return "/admin/variables/%s/" % self.id + def save(self): + super(Variable, self).save() + self.render = self.renderdir + "%s.png" % self.id + super(Variable, self).save() + +dispatcher.connect(update_render, signal=signals.pre_save, sender=Variable) + +class Equation(models.Model): + name = models.CharField(_("Name"), maxlength=256) + latex = models.TextField(_("Raw LaTeX"), unique=True) + unicode = models.TextField(_("Unicode Representation"), blank=True) + description = models.TextField(_("Description"), blank=True) + created = models.DateField(_("Created"), auto_now_add=True) + updated = models.DateField(_("Last Updated"), auto_now_add=True) + owner = models.ForeignKey(auth.User, verbose_name=_("Owner")) + variables = models.ManyToManyField(Variable, verbose_name="Variables", + editable=True) + renderdir = "equationrenders/" + render = models.ImageField(_("Rendered Image"), + upload_to=renderdir, editable=False) + reference = models.URLField(_("Reference URL"), blank=True) + + class Meta: + get_latest_by = 'created' + class Admin: + ordering = ['created'] + + def __str__(self): + return self.name + def get_absolute_url(self): + return "/equation/%s/" % self.id + def get_admin_url(self): + return "/admin/equations/%s/" % self.id + def update_variables(self): + """Updates the variables field with all Variable objects found + in the LaTeX representation.""" + pass # TODO: write + def save(self): + self.update_variables() + super(Equation, self).save() + self.render = self.renderdir + "%s.png" % self.id + super(Equation, self).save() + + +dispatcher.connect(update_render, signal=signals.post_save, sender=Equation) diff --git a/equations/signals.py b/equations/signals.py new file mode 100644 index 0000000..0fecc34 --- /dev/null +++ b/equations/signals.py @@ -0,0 +1,65 @@ +from django.conf import settings + +def update_render(sender, instance, signal, *args, **kwargs): + """Renders an object's .png representation using LaTeX and puts it + in the right directory. Requires latex, dvipng, etc""" + import os, shutil, tempfile, subprocess + def call_command_in_dir(app, args, targetdir): + cwd = os.getcwd() + try: + os.chdir(targetdir) + p = subprocess.Popen(app + ' ' + ' '.join(args), shell=True) + sts = os.waitpid(p.pid, 0) + # FIXME -- should we raise an exception of status is non-zero? + finally: + # Restore working directory + os.chdir(cwd) + + rawlatex = instance.latex + dstdir = settings.MEDIA_ROOT + instance.renderdir + dstfile = "%s.png" % instance.id + dst = "%s" % instance.id + + prologue = "" + latex_template = r''' + \documentclass[12pt]{article} + \pagestyle{empty} + %(prologue)s + \begin{document} + $$%(raw)s$$ + \end{document} + ''' + max_pages = 1 + MAX_RUN_TIME = 5 # seconds + latex = "latex" + dvipng = "dvipng" + latex_args = ("--interaction=nonstopmode", "%s.tex") + dvipng_args = ("-q", "-bgTransparent", "-Ttight", "--noghostscript", + "-l%s" % max_pages, "%s.dvi") + tex = latex_template % { 'raw': rawlatex, 'prologue': prologue } + + tmpdir = tempfile.mkdtemp() + try: + data = open("%s/%s.tex" % (tmpdir, dst), "w") + data.write(tex) + data.close() + args = list(latex_args) + args[-1] = args[-1] % dst + res = call_command_in_dir(latex, args, tmpdir) + if not res is None: + # FIXME need to return some sort of error + return [] + args = list(dvipng_args) + args[-1] = args[-1] % dst + res = call_command_in_dir(dvipng, args, tmpdir) + if not res is None: + # FIXME need to return some sort of error + return [] + + if os.access("%s/%s1.png" % (tmpdir, dst), os.R_OK): + shutil.copyfile("%s/%s1.png" % (tmpdir, dst), + dstdir + dstfile) + finally: + # FIXME do some tidy up here + instance.render = instance.renderdir + dstfile + shutil.rmtree(tmpdir) diff --git a/equations/templates/equations/equation_detail.html b/equations/templates/equations/equation_detail.html new file mode 100644 index 0000000..b4c3911 --- /dev/null +++ b/equations/templates/equations/equation_detail.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block title %}{{ object.name }}{% endblock %} + +{% block content %} +
+
+ +{% if object.description %} + +{% endif %} +{% if object.variables %} + +{% if object.unicode %} + +{% endif %} + +
Description:{{ object.description }}
Variables: + {% for variable in object.variables %} + {{ variable.name }}
+ {% endfor %} +{% endif %} +
Raw LaTeX:{{ object.latex }}
Unicode:{{ object.unicode }}

+ This equation was created on {{ object.created }}; + it was last updated on {{ object.updated }}. It's owner is + {{ object.owner }}.
+{% endblock %} diff --git a/equations/templates/equations/equation_list.html b/equations/templates/equations/equation_list.html new file mode 100644 index 0000000..c7a9632 --- /dev/null +++ b/equations/templates/equations/equation_list.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block title %}Check out all these equations!{% endblock %} + +{% block content %} +{% if object_list %} + + {% for item in object_list %} + + {% endfor %} +
+ + + + {{ item.name }}
+{% if not is_paginated %}
{% if not has_previous %} +<PREV +{% endif %}{% if has_next %} +NEXT> +{% endif %}{% endif %} +{% else %} +Fuck, where are they? +{% endif %} +{% endblock %} diff --git a/equations/views.py b/equations/views.py index 60f00ef..8e2f6fa 100644 --- a/equations/views.py +++ b/equations/views.py @@ -1 +1,30 @@ -# Create your views here. +from django.core import serializers +from models import Equation, Variable, Symbol +from django.http import HttpResponse + +def all_vars(request): + data = serializers.serialize("json", Variable.objects.all()) + return HttpResponse(data, mimetype="text/javascript") + +def all_symbs(request): + data = serializers.serialize("json", Symbol.objects.all()) + return HttpResponse(data, mimetype="text/javascript") + +def equs_by_vars(request, whichvars): + vars = whichvars.split(',') + if len(vars) < 1: + return HttpResponse('[]', mimetype="text/javascript") + #if vars[-1] == '/': + # vars = vars[:-1] + returnables = Equation.objects.filter(variables=vars[0]) + if len(vars) > 1: + for r in returnables: + for i in vars[1:]: + if not i in r.variables: + returnables = returnables.exclude(id=r.id) + if len(returnables) < 1: + break + + data = serializers.serialize("json", returnables) + return HttpResponse(data, mimetype="text/javascript") + diff --git a/settings.py.example b/settings.py.example new file mode 100644 index 0000000..432bc77 --- /dev/null +++ b/settings.py.example @@ -0,0 +1,87 @@ +# Django settings for equator project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@domain.com'), +) + +MANAGERS = ADMINS + +DATABASE_ENGINE = 'sqlite3' # 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'. +DATABASE_NAME = 'equator/eq.db' # Or path to database file if using sqlite3. +DATABASE_USER = '' # Not used with sqlite3. +DATABASE_PASSWORD = '' # Not used with sqlite3. +DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. +DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. + +# Local time zone for this installation. All choices can be found here: +# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'America/Boston' + +# Language code for this installation. All choices can be found here: +# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes +# http://blogs.law.harvard.edu/tech/stories/storyReader$15 +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# Absolute path to the directory that holds media. +# Example: "/home/media/media.lawrence.com/" +MEDIA_ROOT = 'equator/static/' + +# URL that handles the media served from MEDIA_ROOT. +# Example: "http://media.lawrence.com" +MEDIA_URL = '/static/' + +# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a +# trailing slash. +# Examples: "http://foo.com/media/", "/media/". +ADMIN_MEDIA_PREFIX = '/static/admin-media/' + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'changeme' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.load_template_source', + 'django.template.loaders.app_directories.load_template_source', +# 'django.template.loaders.eggs.load_template_source', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware', + 'django.contrib.csrf.middleware.CsrfMiddleware', + 'django.middleware.doc.XViewMiddleware', +) + +ROOT_URLCONF = 'equator.urls' + +TEMPLATE_DIRS = ( + 'equator/templates/', + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.admin', + 'django.contrib.flatpages', + 'django.contrib.markup', + 'django.contrib.comments', + 'equator.equations', +) diff --git a/templates/base.html b/templates/base.html index c2e023b..82579c5 100644 --- a/templates/base.html +++ b/templates/base.html @@ -9,7 +9,7 @@
-

{% block title %}The Equator% endblock %}

+

{% block title %}The Equator{% endblock %}

{% block content %} no content? diff --git a/templates/go.html b/templates/go.html index cb1e855..5569cf2 100644 --- a/templates/go.html +++ b/templates/go.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% block javascript %} -