Skip to content

Instantly share code, notes, and snippets.

@kaedroho
Last active August 29, 2015 13:57
Show Gist options
  • Save kaedroho/9537074 to your computer and use it in GitHub Desktop.
Save kaedroho/9537074 to your computer and use it in GitHub Desktop.
PR144 description
# This gist describes the changes I have made in PR #144
# Add AJAX template (1cb7dcb0b29bd2d20016515b922cfc9ca8de9be4)
# ============================================================
# The first of my changes is allowing ajax templates to be specified as an attribute to the page class.
# I created a method called get_template() which finds the best template to use for a particular request.
# This function is overridable so a developer can have a more advanced configuration if they want.
# If this is not filled out, the ajax template will fall back to the standard template.
# This addresses a very common pattern in the RCA source.
# Example: https://github.com/torchbox/verdant-rca/blob/master/django-verdant/rca/models.py#L2473-L2482
# Heres an example of how this will be used (quite obvious really):
class BlogIndex(Page):
...
ajax_template = 'blog_listing.html'
# Add get_context method (16db4fdc7e47a04389c195124ce471ff83109adb)
# =================================================================
# Instead of overriding the serve method, I think in most cases
# developers should really be overriding a get_context method.
# The one major advantage this change brings is that it makes it much easier for a
# subclass to extend a superclasses context variables
# Heres an example
class Restraunt(Page):
def get_context(self, request):
# Get context of superclass
context = super(Restraunt, self).get_context(request)
# Add some context variables to the restraunt template
context['foo'] = request.GET.get('foo', None)
context['bar'] = "Bar"
return context
class ItalianRestraunt(Restraunt):
def get_context(self, request):
# Get context of restraunt
context = super(Restraunt, self).get_context(request)
# Add a variable specific to italian restraunts
context['serves_pizza'] = True
return context
# Add process_request method (7b88d2c1bf4f3ea33c865cf7f23146479e8fa0fa)
# =====================================================================
# This new method gets called at every step in the URL resolution.
# For example, if somebody requested "/blog/hello-world/" the process_request
# method will be run on the pages in the following order:
# - The root page
# - The blog index at "/blog/"
# - The blog entry at "/blog/hello-world/" (where it returns a response)
# It works in a very similar way to Django middleware works (hence the name) -- the
# first one of these pages to return a response will be the page thats rendered.
# This method is only called when the page is live.
# This change gives two (pretty small, but I think warranted) advantages:
# 1. It provides a place where a page can add data to a request object for a subpage to read.
# This is beneficial in cases where you want to reliably work out which index page a blog post is in.
class BlogIndex(Page):
def process_request(self, request, path):
# Add reference to blog index to the request object
request.blog_index = self
return super(BlogIndex, self).process_request(request, path)
class BlogEntry(Page):
def get_context(self, request):
context = super(BlogEntry, self).get_context()
# Add blog index to context
context['blog_index'] = request.blog_index
return context
# 2. (I think) Calling process_request directly is better than calling route directly.
# I think this because process_request will either return a response for the current page or None
# which makes generating page previews and testing much easier when custom routing is being used.
# Also, overriding route will require the developer to remember to put an "if page.live == True" check
# into their code.
# Added SuperPage class (2da651abf05091e5b0cccfbd2cfbb770649fd874)
# ================================================================
# I'm not decided on the name yet, or on whether or not this should be in the main Page class.
# This class allows a developer to embed a urlconf into a page. This makes custom routing much easier.
# It includes methods for both resolving and reversing urls on a page object.
# Heres an example of how subpages are configured on "SuperPages":
class TestSuperPage(SuperPage):
def get_subpage_urls(self):
return [
self.subpage_url(r'^$', self.serve, name='main'),
self.subpage_url(r'^blog/$', self.blog_index, name='blog_index'),
self.subpage_url(r'^blog/(\w+)$', self.blog_entry, name='blog_entry'),
]
def blog_index(self, request):
return render(request, 'blog_index.html')
def blog_entry(self, request, name):
blog = get_object_or_404(BlogEntry, name=name)
return render(request, 'blog_entry.html', {
'blog': blog,
})
# You can reverse urls on SuperPages by using the "reverse_subpage" method.
# For example, lets say we created an instance of the above class at "/test/"
>>> page.reverse_subpage('main')
'/test/'
>>> page.reverse_subpage('blog_index')
'/test/blog/'
>>> page.reverse_subpage('blog_index', 'hello')
'/test/blog/hello/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment