Index: django/contrib/dbtemplates/sync_templates.py
===================================================================
--- django/contrib/dbtemplates/sync_templates.py	(Revision 0)
+++ django/contrib/dbtemplates/sync_templates.py	(Revision 0)
@@ -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()
Index: django/contrib/dbtemplates/__init__.py
===================================================================
Index: django/contrib/dbtemplates/models.py
===================================================================
--- django/contrib/dbtemplates/models.py	(Revision 0)
+++ django/contrib/dbtemplates/models.py	(Revision 0)
@@ -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
+<Site: example.com>
+>>> t1 = Template(name='base.html', content="<html><head></head><body>{% block content %}Welcome at {{ title }}{% endblock %}</body></html>")
+>>> t1.save()
+>>> t1.sites.add(test_site)
+>>> t1
+<Template: base.html>
+>>> t2 = Template(name='sub.html', content='{% extends "base.html" %}{% block content %}This is {{ title }}{% endblock %}')
+>>> t2.save()
+>>> t2.sites.add(test_site)
+>>> t2
+<Template: sub.html>
+>>> Template.objects.filter(sites=test_site)
+[<Template: base.html>, <Template: sub.html>]
+>>> t2.sites.all()
+[<Site: example.com>]
+>>> 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'}))
+'<html><head></head><body>Welcome at MainPage</body></html>'
+>>> loader.get_template("sub.html").render(Context({'title':'SubPage'}))
+'<html><head></head><body>This is SubPage</body></html>'
+"""}
Index: django/contrib/dbtemplates/loader.py
===================================================================
--- django/contrib/dbtemplates/loader.py	(Revision 0)
+++ django/contrib/dbtemplates/loader.py	(Revision 0)
@@ -0,0 +1,25 @@
+# Wrapper for loading templates from the database.
+
+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
Index: tests/runtests.py
===================================================================
--- tests/runtests.py	(Revision 5383)
+++ tests/runtests.py	(Arbeitskopie)
@@ -24,6 +24,7 @@
     'django.contrib.sessions',
     'django.contrib.comments',
     'django.contrib.admin',
+    'django.contrib.dbtemplates',
 ]
 
 def get_test_models():
