From bbc00a779b032b7d078bb65c3a9d3290d142b4b4 Mon Sep 17 00:00:00 2001 From: leidel Date: Fri, 20 Jul 2007 14:30:48 +0000 Subject: [PATCH] again: refactoring as a standalone application git-svn-id: https://django-dbtemplates.googlecode.com/svn/trunk@12 cfb8ba98-e953-0410-9cff-959ffddf5974 committer: leidel --HG-- extra : convert_revision : 5fc12102108671ddb3b9890c9091bd39cb446728 --- LICENSE | 28 ++++++++++++ README | 55 ++++++++++++++++++++++++ dbtemplates/__init__.py | 0 dbtemplates/loader.py | 23 ++++++++++ dbtemplates/management.py | 36 ++++++++++++++++ dbtemplates/models.py | 56 ++++++++++++++++++++++++ dbtemplates/sync_templates.py | 80 +++++++++++++++++++++++++++++++++++ 7 files changed, 278 insertions(+) create mode 100644 LICENSE create mode 100644 README create mode 100644 dbtemplates/__init__.py create mode 100644 dbtemplates/loader.py create mode 100644 dbtemplates/management.py create mode 100644 dbtemplates/models.py create mode 100644 dbtemplates/sync_templates.py diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2182ba1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2007, Jannis Leidel +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the author nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README b/README new file mode 100644 index 0000000..72af47f --- /dev/null +++ b/README @@ -0,0 +1,55 @@ +Database template loader for Django +=================================== + +This is a basic database template loader for Django which uses a m2m +relationship to provide a site centric template loading. + +How to use it in your own django application +============================================ + +0. Get the source from the subversion repository +1. Copy the "template" directory to your django project directory +2. Edit your settings.py: + + # Add ``myapp.template`` to the ``INSTALLED_APPS`` where "myapp" is the + name of your django project + + # Check if ``django.contrib.sites`` and ``django.contrib.admin`` are in + ``INSTALLED_APPS`` and add if necessary + + It should look something like this: + + INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.admin', + 'django.contrib.flatpages', + 'myapp.blog', + 'myapp.template', + ) + + # Add ``myapp.template.loaders.database.load_template_source`` to the + ``TEMPLATE_LOADERS`` where "myapp" is the name of your Django project + + It should look something like this: + + TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.load_template_source', + 'django.template.loaders.app_directories.load_template_source', + 'myapp.template.loaders.database.load_template_source', + ) + +3. Sync your database via shell (hint: "./manage.py syncdb" within project dir) +4. Restart your Django server +5. Go to the admin interface and add templates by filling the ``name`` field +with filename like identifiers, for example "blog/entry_list.html" +6. Use it with ``Flatpages``, ``Generic views`` and your own custom views + +What? Hm, doesn't work here. || Aaah nice, BUT... +================================================= + +Please leave your questions and messages on the designated Google Code site: + + http://code.google.com/p/django-databasetemplateloader/ diff --git a/dbtemplates/__init__.py b/dbtemplates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dbtemplates/loader.py b/dbtemplates/loader.py new file mode 100644 index 0000000..91f0e76 --- /dev/null +++ b/dbtemplates/loader.py @@ -0,0 +1,23 @@ +from django.conf import settings +from django.template import TemplateDoesNotExist +from django.contrib.dbtemplates.models import Template +from django.contrib.sites.models import Site + +try: + site = Site.objects.get_current() +except: + site = None + +def load_template_source(template_name, template_dirs=None): + """ + Loads templates from the database by querying the database field ``name`` + with a template path and ``sites`` with the current site. + """ + if site is not None: + try: + t = Template.objects.get(name__exact=template_name, sites__pk=site.id) + return (t.content, 'db:%s:%s' % (settings.DATABASE_ENGINE, template_name)) + except: + pass + raise TemplateDoesNotExist, template_name +load_template_source.is_usable = True \ No newline at end of file diff --git a/dbtemplates/management.py b/dbtemplates/management.py new file mode 100644 index 0000000..06d2cfd --- /dev/null +++ b/dbtemplates/management.py @@ -0,0 +1,36 @@ +""" +Creates the default database template objects. +Don't know if it works. +""" + +from django.dispatch import dispatcher +from django.db.models import signals +from django.contrib.sites.models import Site + +from template.models import Template +from template import models as template_app + +def create_default_templates(app, created_models, verbosity): + try: + site = Site.objects.get_current() + except Site.DoesNotExist: + site = None + + if site is not None: + if Template in created_models: + if verbosity >= 2: + print "Creating example database templates for error 404 and error 500" + + template404 = Template(name="404.html",content=""" + {% load i18n %}

{% trans 'Page not found' %}

+

{% trans "We're sorry, but the requested page could not be found." %}

""") + template404.save() + template404.sites.add(site) + + template500 = Template(name="500.html",content="""{% load i18n %} +

{% trans 'Server Error (500)' %}

+

{% trans "There's been an error." %}

""") + template500.save() + template500.sites.add(site) + +dispatcher.connect(create_default_templates, sender=template_app, signal=signals.post_syncdb) diff --git a/dbtemplates/models.py b/dbtemplates/models.py new file mode 100644 index 0000000..807c37f --- /dev/null +++ b/dbtemplates/models.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +from django.db import models +from django.template import loader, Context +from django.core import validators +from django.contrib.sites.models import Site +from django.utils.translation import gettext_lazy as _ + +class Template(models.Model): + """ + Defines a template model for use with the database template loader. + The field ``name`` is the equivalent to the filename of a static template. + """ + name = models.CharField(_('name'), unique=True, maxlength=100, help_text=_("Example: 'flatpages/default.html'")) + content = models.TextField(_('content')) + sites = models.ManyToManyField(Site) + creation_date = models.DateTimeField(_('creation date'), auto_now_add=True) + last_changed = models.DateTimeField(_('last changed'), auto_now=True) + class Meta: + db_table = 'django_template' + verbose_name = _('template') + verbose_name_plural = _('templates') + ordering = ('name',) + class Admin: + fields = ((None, {'fields': ('name', 'content', 'sites')}),) + list_display = ('name', 'creation_date', 'last_changed') + list_filter = ('sites',) + search_fields = ('name','content') + + def __str__(self): + return self.name + +__test__ = {'API_TESTS':""" +>>> test_site = Site.objects.get(pk=1) +>>> test_site + +>>> t1 = Template(name='base.html', content="{% block content %}Welcome at {{ title }}{% endblock %}") +>>> t1.save() +>>> t1.sites.add(test_site) +>>> t1 + +>>> t2 = Template(name='sub.html', content='{% extends "base.html" %}{% block content %}This is {{ title }}{% endblock %}') +>>> t2.save() +>>> t2.sites.add(test_site) +>>> t2 + +>>> Template.objects.filter(sites=test_site) +[, ] +>>> t2.sites.all() +[] +>>> from django.contrib.dbtemplates.loader import load_template_source +>>> loader.template_source_loaders = [load_template_source] +>>> loader.get_template("base.html").render(Context({'title':'MainPage'})) +'Welcome at MainPage' +>>> loader.get_template("sub.html").render(Context({'title':'SubPage'})) +'This is SubPage' +"""} \ No newline at end of file diff --git a/dbtemplates/sync_templates.py b/dbtemplates/sync_templates.py new file mode 100644 index 0000000..4a06b9d --- /dev/null +++ b/dbtemplates/sync_templates.py @@ -0,0 +1,80 @@ +""" +Helper function for syncing templates in TEMPLATES_DIRS with the dbtemplates +contrib app. +""" + +from django.conf import settings +from django.template import TemplateDoesNotExist +from django.contrib.dbtemplates.models import Template +from django.contrib.sites.models import Site + +import os +import sys + +try: + site = Site.objects.get_current() +except: + site = None + +def synctemplates(extension=".html", overwrite=False): + """ + Helper function for syncing templates in TEMPLATES_DIRS with the + dbtemplates contrib app. + """ + tried = [] + synced = [] + existing = [] + overwritten = [] + + if site is not None: + for template_dir in settings.TEMPLATE_DIRS: + if os.path.isdir(template_dir): + for dirpath, subdirs, filenames in os.walk(template_dir): + for file in filenames: + if file.endswith(extension) and not file.startswith("."): + filepath = os.path.join(dirpath, file) + filename = filepath.split(template_dir)[1][1:] + try: + try: + t = Template.objects.get(name__exact=filename) + except Template.DoesNotExist: + filecontent = open(filepath, "r").read() + t = Template(name=filename, content=filecontent) + t.save() + t.sites.add(site) + synced.append(filename) + else: + if overwrite: + t.content = open(filepath, "r").read() + t.save() + t.sites.add(site) + overwritten.append(t.name) + else: + existing.append(t.name) + except IOError: + tried.append(filepath) + except: + raise TemplateDoesNotExist + + if len(existing) > 0: + print "\nAlready existing templates:" + for _existing in existing: + print _existing + + if len(overwritten) > 0: + print "\nOverwritten existing templates:" + for _replaced in overwritten: + print _replaced + + if len(synced) > 0: + print "\nSuccessfully synced templates:" + for _synced in synced: + print _synced + + if len(tried) > 0: + print "\nTried to sync but failed:" + for _tried in tried: + print _tried + +if __name__ == "__main__": + synctemplates() \ No newline at end of file