[cig-commits] r6218 - in cs/pythia/trunk/opal: components core
core/handlers db sites views views/generic
leif at geodynamics.org
leif at geodynamics.org
Fri Mar 9 19:09:04 PST 2007
Author: leif
Date: 2007-03-09 19:09:03 -0800 (Fri, 09 Mar 2007)
New Revision: 6218
Added:
cs/pythia/trunk/opal/components/WebComponent.py
cs/pythia/trunk/opal/db/queries.py
cs/pythia/trunk/opal/views/DetailView.py
cs/pythia/trunk/opal/views/ListView.py
cs/pythia/trunk/opal/views/PaginatedListView.py
cs/pythia/trunk/opal/views/View.py
Removed:
cs/pythia/trunk/opal/views/generic/list_detail.py
Modified:
cs/pythia/trunk/opal/core/handlers/base.py
cs/pythia/trunk/opal/core/urlresolvers.py
cs/pythia/trunk/opal/sites/WebSite.py
cs/pythia/trunk/opal/views/__init__.py
Log:
Sketched-out OOP-ized object_list and object_detail. Added the germ
of my idea of how URLResolvers should work.
Added: cs/pythia/trunk/opal/components/WebComponent.py
===================================================================
--- cs/pythia/trunk/opal/components/WebComponent.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/components/WebComponent.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# California Institute of Technology
+# (C) 2007 All Rights Reserved
+#
+# {LicenseText}
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+
+
+from pyre.components import Component
+
+
+class WebComponent(Component):
+
+
+ children = {}
+
+
+ def view(self):
+ return self.DefaultViewClass(self)
+
+
+# end of file
Modified: cs/pythia/trunk/opal/core/handlers/base.py
===================================================================
--- cs/pythia/trunk/opal/core/handlers/base.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/core/handlers/base.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -50,7 +50,7 @@
def get_response(self, path, request):
"Returns an HttpResponse object for the given HttpRequest"
- from opal.core import exceptions, urlresolvers
+ from opal.core import exceptions
from opal.core.mail import mail_admins
from opal.conf import settings
@@ -60,9 +60,9 @@
if response:
return response
- resolver = urlresolvers.RegexURLResolver(r'^/', settings.ROOT_URLCONF)
try:
- callback, callback_args, callback_kwargs = resolver.resolve(path)
+ site = settings
+ callback, callback_args, callback_kwargs = site.resolve(path)
# Apply view middleware
for middleware_method in self._view_middleware:
Modified: cs/pythia/trunk/opal/core/urlresolvers.py
===================================================================
--- cs/pythia/trunk/opal/core/urlresolvers.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/core/urlresolvers.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -217,3 +217,23 @@
urlconf = settings.ROOT_URLCONF
resolver = RegexURLResolver(r'^/', urlconf)
return '/' + resolver.reverse(viewname, *args, **kwargs)
+
+class TreeURLResolver(object):
+ def __init__(self, root):
+ self.root = root
+
+ def resolve(self, pathname):
+ #raise Resolver404, {'tried': ['foo', 'bar', path], 'path': path + 'hey'}
+ path = pathname.split('/')
+ args = ()
+ kwargs = {}
+ node = self.root
+ try:
+ for name in path[:-1]:
+ node = node.children[name]
+ name = path[-1]
+ if name != "":
+ node = node.children[name]
+ except KeyError:
+ raise Http404
+ return node.view().response, args, kwargs
Added: cs/pythia/trunk/opal/db/queries.py
===================================================================
--- cs/pythia/trunk/opal/db/queries.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/db/queries.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# California Institute of Technology
+# (C) 2007 All Rights Reserved
+#
+# {LicenseText}
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+
+
+class Query(object):
+
+ def apply(self, queryset):
+ raise NotImplementedError()
+
+ def get(self, queryset):
+ queryset = self.apply(queryset)
+ return queryset.get()
+
+
+class ObjectIdQuery(Query):
+
+ def __init__(self, object_id):
+ Query.__init__(self)
+ self.object_id = object_id
+
+ def apply(self, queryset):
+ return queryset.filter(pk=self.object_id)
+
+ def __str__(self):
+ return "object_id=%s" % self.object_id
+
+
+class ObjectSlugQuery(Query):
+
+ def __init__(self, slug, slug_field):
+ Query.__init__(self)
+ self.slug = slug
+ self.slug_field = slug_field
+
+ def apply(self, queryset):
+ return queryset.filter(**{self.slug_field: self.slug})
+
+ def __str__(self):
+ return "%s='%s'" % (self.slug_field, self.slug)
+
+
+def objectQuery(object_id=None, slug=None, slug_field=None):
+ if object_id:
+ query = ObjectIdQuery(object_id)
+ elif slug and slug_field:
+ query = ObjectSlugQuery(slug, slug_field)
+ else:
+ raise AttributeError, "Object query must be created with either an object_id or a slug/slug_field."
+ return query
+
+
+# end of file
Modified: cs/pythia/trunk/opal/sites/WebSite.py
===================================================================
--- cs/pythia/trunk/opal/sites/WebSite.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/sites/WebSite.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -316,7 +316,7 @@
#########
SITE_ID = pyre.int("site-id", default=1)
- ROOT_URLCONF = pyre.str("root-urlconf", default="not.yet.implemented")
+ xROOT_URLCONF = pyre.str("root-urlconf", default="not.yet.implemented")
def _configure(self):
@@ -333,4 +333,24 @@
return
+ ##########
+
+
+ urlpatterns = None
+
+
+ def resolve(self, path):
+ resolver = self.urlResolver()
+ return resolver.resolve(path)
+
+
+ def urlResolver(self):
+ from opal.core import urlresolvers
+ if self.urlpatterns is None:
+ resolver = urlresolvers.TreeURLResolver(self)
+ else:
+ resolver = urlresolvers.RegexURLResolver(r'^/', self)
+ return resolver
+
+
# end of file
Added: cs/pythia/trunk/opal/views/DetailView.py
===================================================================
--- cs/pythia/trunk/opal/views/DetailView.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/views/DetailView.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# California Institute of Technology
+# (C) 2007 All Rights Reserved
+#
+# {LicenseText}
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+
+
+from View import View
+from opal.template import RequestContext
+from opal.http import Http404, HttpResponse
+from opal.core.xheaders import populate_xheaders
+
+
+class DetailView(View):
+ """
+ Generic view of an object.
+
+ Templates: ``<app_label>/<model_name>_detail.html``
+ Context:
+ object
+ the object
+ """
+
+
+ templateNameTag = "detail"
+
+
+ def __init__(self, queryset, query,
+ template_name_field=None, **kwds):
+ View.__init__(self, queryset=queryset, **kwds)
+ self.query = query
+ self.template_name_field = template_name_field
+ return
+
+
+ def response(self, request):
+ model = self.queryset.model
+ try:
+ obj = self.query.get(self.queryset)
+ except ObjectDoesNotExist:
+ raise Http404, "No %s found matching the query '%s'" % (model._meta.verbose_name, query)
+ t = self.loadTemplate(obj)
+ c = RequestContext(request, {template_object_name: obj}, self.context_processors)
+ c = self.addExtraContext(c)
+ response = HttpResponse(t.render(c), mimetype=self.mimetype)
+ populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
+ return response
+
+
+ def loadTemplate(self, obj):
+ if self.template_name_field:
+ template_name_list = [getattr(obj, self.template_name_field), self.template_name]
+ t = self.template_loader.select_template(template_name_list)
+ else:
+ t = super(DetailView, self).loadTemplate()
+ return t
+
+
+# end of file
Added: cs/pythia/trunk/opal/views/ListView.py
===================================================================
--- cs/pythia/trunk/opal/views/ListView.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/views/ListView.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# California Institute of Technology
+# (C) 2007 All Rights Reserved
+#
+# {LicenseText}
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+
+
+from View import View
+from opal.template import RequestContext
+from opal.http import Http404, HttpResponse
+
+
+class ListView(View):
+ """
+ Generic list of objects.
+
+ Templates: ``<app_label>/<model_name>_list.html``
+ Context:
+ object_list
+ list of objects
+ is_paginated
+ are the results paginated?
+ results_per_page
+ number of objects per page (if paginated)
+ has_next
+ is there a next page?
+ has_previous
+ is there a prev page?
+ page
+ the current page
+ next
+ the next page
+ previous
+ the previous page
+ pages
+ number of pages, total
+ hits
+ number of objects, total
+ """
+
+
+ templateNameTag = "list"
+
+
+ def __init__(self, queryset, allow_empty=True, **kwds):
+ View.__init__(self, queryset=queryset, **kwds)
+ self.allow_empty = allow_empty
+ return
+
+
+ def response(self, request):
+ c = self.requestContext(request)
+ c = self.addExtraContext(c)
+ t = self.loadTemplate()
+ return HttpResponse(t.render(c), mimetype=self.mimetype)
+
+
+ def requestContext(self, request):
+ c = RequestContext(request, {
+ '%s_list' % self.template_object_name: self.queryset,
+ 'is_paginated': False
+ }, self.context_processors)
+ if not self.allow_empty and len(self.queryset) == 0:
+ raise Http404
+ return c
+
+
+# end of file
Added: cs/pythia/trunk/opal/views/PaginatedListView.py
===================================================================
--- cs/pythia/trunk/opal/views/PaginatedListView.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/views/PaginatedListView.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# California Institute of Technology
+# (C) 2007 All Rights Reserved
+#
+# {LicenseText}
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+
+
+from ListView import ListView
+from opal.core.paginator import ObjectPaginator, InvalidPage
+from opal.template import RequestContext
+
+
+class PaginatedListView(ListView):
+ """
+ Paginated list of objects.
+
+ Templates: ``<app_label>/<model_name>_list.html``
+ Context:
+ object_list
+ list of objects
+ is_paginated
+ are the results paginated?
+ results_per_page
+ number of objects per page (if paginated)
+ has_next
+ is there a next page?
+ has_previous
+ is there a prev page?
+ page
+ the current page
+ next
+ the next page
+ previous
+ the previous page
+ pages
+ number of pages, total
+ hits
+ number of objects, total
+ """
+
+
+ def __init__(self, queryset, paginate_by, page=None, **kwds):
+ ListView.__init__(queryset=queryset, **kwds)
+ self.paginate_by = paginate_by
+ self.page = page
+ return
+
+
+ def requestContext(self, request):
+ queryset = self.queryset._clone()
+ paginator = ObjectPaginator(queryset, self.paginate_by)
+ page = self.page
+ if not page:
+ page = request.GET.get('page', 1)
+ try:
+ page = int(page)
+ object_list = paginator.get_page(page - 1)
+ except (InvalidPage, ValueError):
+ if page == 1 and self.allow_empty:
+ object_list = []
+ else:
+ raise Http404
+ c = RequestContext(request, {
+ '%s_list' % self.template_object_name: object_list,
+ 'is_paginated': paginator.pages > 1,
+ 'results_per_page': self.paginate_by,
+ 'has_next': paginator.has_next_page(page - 1),
+ 'has_previous': paginator.has_previous_page(page - 1),
+ 'page': page,
+ 'next': page + 1,
+ 'previous': page - 1,
+ 'pages': paginator.pages,
+ 'hits' : paginator.hits,
+ }, self.context_processors)
+ return c
+
+
+# end of file
Added: cs/pythia/trunk/opal/views/View.py
===================================================================
--- cs/pythia/trunk/opal/views/View.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/views/View.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# California Institute of Technology
+# (C) 2007 All Rights Reserved
+#
+# {LicenseText}
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+
+
+class View(object):
+
+
+ def __init__(self, queryset,
+ template_name=None, template_loader=None,
+ extra_context=None, context_processors=None,
+ template_object_name='object',
+ mimetype=None):
+ self.queryset = queryset
+ if template_name:
+ self.template_name = template_name
+ else:
+ model = queryset.model
+ template_name = "%s/%s_%s.html" % (model._meta.app_label,
+ model._meta.object_name.lower(),
+ self.templateNameTag)
+ if template_loader is None:
+ from opal.template import loader
+ self.template_loader = loader
+ else:
+ self.template_loader = template_loader
+ if extra_context is None:
+ self.extra_context = {}
+ else:
+ self.extra_context = extra_context
+ self.context_processors = context_processors
+ self.template_object_name = template_object_name
+ self.mimetype = mimetype
+ return
+
+
+ def response(self):
+ raise NotImplementedError("class %r must override 'response'" % self.__class__.__name__)
+
+
+ def loadTemplate(self):
+ return self.template_loader.get_template(self.template_name)
+
+
+ def addExtraContext(self, c):
+ for key, value in self.extra_context.items():
+ if callable(value):
+ c[key] = value()
+ else:
+ c[key] = value
+ return c
+
+
+# end of file
Modified: cs/pythia/trunk/opal/views/__init__.py
===================================================================
--- cs/pythia/trunk/opal/views/__init__.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/views/__init__.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# California Institute of Technology
+# (C) 2007 All Rights Reserved
+#
+# {LicenseText}
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+
+
+from View import View
+from DetailView import DetailView
+from ListView import ListView
+from PaginatedListView import PaginatedListView
+
+
+# end of file
Deleted: cs/pythia/trunk/opal/views/generic/list_detail.py
===================================================================
--- cs/pythia/trunk/opal/views/generic/list_detail.py 2007-03-10 01:32:55 UTC (rev 6217)
+++ cs/pythia/trunk/opal/views/generic/list_detail.py 2007-03-10 03:09:03 UTC (rev 6218)
@@ -1,123 +0,0 @@
-from opal.template import loader, RequestContext
-from opal.http import Http404, HttpResponse
-from opal.core.xheaders import populate_xheaders
-from opal.core.paginator import ObjectPaginator, InvalidPage
-from opal.core.exceptions import ObjectDoesNotExist
-
-def object_list(request, queryset, paginate_by=None, page=None,
- allow_empty=False, template_name=None, template_loader=loader,
- extra_context=None, context_processors=None, template_object_name='object',
- mimetype=None):
- """
- Generic list of objects.
-
- Templates: ``<app_label>/<model_name>_list.html``
- Context:
- object_list
- list of objects
- is_paginated
- are the results paginated?
- results_per_page
- number of objects per page (if paginated)
- has_next
- is there a next page?
- has_previous
- is there a prev page?
- page
- the current page
- next
- the next page
- previous
- the previous page
- pages
- number of pages, total
- hits
- number of objects, total
- """
- if extra_context is None: extra_context = {}
- queryset = queryset._clone()
- if paginate_by:
- paginator = ObjectPaginator(queryset, paginate_by)
- if not page:
- page = request.GET.get('page', 1)
- try:
- page = int(page)
- object_list = paginator.get_page(page - 1)
- except (InvalidPage, ValueError):
- if page == 1 and allow_empty:
- object_list = []
- else:
- raise Http404
- c = RequestContext(request, {
- '%s_list' % template_object_name: object_list,
- 'is_paginated': paginator.pages > 1,
- 'results_per_page': paginate_by,
- 'has_next': paginator.has_next_page(page - 1),
- 'has_previous': paginator.has_previous_page(page - 1),
- 'page': page,
- 'next': page + 1,
- 'previous': page - 1,
- 'pages': paginator.pages,
- 'hits' : paginator.hits,
- }, context_processors)
- else:
- c = RequestContext(request, {
- '%s_list' % template_object_name: queryset,
- 'is_paginated': False
- }, context_processors)
- if not allow_empty and len(queryset) == 0:
- raise Http404
- for key, value in extra_context.items():
- if callable(value):
- c[key] = value()
- else:
- c[key] = value
- if not template_name:
- model = queryset.model
- template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower())
- t = template_loader.get_template(template_name)
- return HttpResponse(t.render(c), mimetype=mimetype)
-
-def object_detail(request, queryset, object_id=None, slug=None,
- slug_field=None, template_name=None, template_name_field=None,
- template_loader=loader, extra_context=None,
- context_processors=None, template_object_name='object',
- mimetype=None):
- """
- Generic list of objects.
-
- Templates: ``<app_label>/<model_name>_detail.html``
- Context:
- object
- the object
- """
- if extra_context is None: extra_context = {}
- model = queryset.model
- if object_id:
- queryset = queryset.filter(pk=object_id)
- elif slug and slug_field:
- queryset = queryset.filter(**{slug_field: slug})
- else:
- raise AttributeError, "Generic detail view must be called with either an object_id or a slug/slug_field."
- try:
- obj = queryset.get()
- except ObjectDoesNotExist:
- raise Http404, "No %s found matching the query" % (model._meta.verbose_name)
- if not template_name:
- template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
- if template_name_field:
- template_name_list = [getattr(obj, template_name_field), template_name]
- t = template_loader.select_template(template_name_list)
- else:
- t = template_loader.get_template(template_name)
- c = RequestContext(request, {
- template_object_name: obj,
- }, context_processors)
- for key, value in extra_context.items():
- if callable(value):
- c[key] = value()
- else:
- c[key] = value
- response = HttpResponse(t.render(c), mimetype=mimetype)
- populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
- return response
More information about the cig-commits
mailing list