Configuring where detail pages are built¶
If you are seeking to publish a detail page for each record in a database model, our recommended way is using the BuildableDetailView.
When the view is executed via bakery’s standard build process, it will loop
through each object in the table and build a corresponding page at a path determined by
the view’s get_url
method.
You can override get_url
to build the pages anywhere you want, but the easiest
route is by configuring Django’s standard get_absolute_url
method on the model, which is where get_url
looks by default.
Here’s an example. Let’s start with a model that will contain a record for each
of America’s 50 states. Notice how we have defined Django’s standard get_absolute_url
method to return a URL that features each state’s unique postal code.
from django.db import models
from bakery.models import BuildableModel
class State(BuildableModel):
name = models.CharField(max_length=100)
postal_code = models.CharField(max_length=2, unique=True)
def get_absolute_url(self):
return '/%s/' % self.postal_code
That model is then connected to a BuildableDetailView
that can create a page
for every state.
from myapp.models import State
from bakery.views import BuildableDetailView
class StateDetailView(BuildableDetailView):
model = State
template_name = 'state_detail.html'
As described in the getting started guide, that view will need to be added
to the BAKERY_VIEWS
list in settings.py
.
Now, because the URL has been preconfigured with get_absolute_url
, all 50 pages
can be built with the standard management command (assuming your settings have
been properly configured).
$ python manage.py build
That will create pages like this in the build directory.
build/AL/index.html
build/AK/index.html
build/AR/index.html
build/AZ/index.html
build/CA/index.html
build/CO/index.html
... etc ...
If you wanted to build objects using a pattern independent of the model, you can instead
override the get_url
method on the BuildableDetailView
.
from myapp.models import State
from bakery.views import BuildableDetailView
class ExampleDetailView(BuildableDetailView):
model = State
template_name = 'state_detail.html'
def get_url(self, obj):
return '/my-fancy-pattern/state/%s/' % obj.postal_code
That will create pages like this in the build directory.
build/my-fancy-pattern/state/AL/index.html
build/my-fancy-pattern/state/AK/index.html
build/my-fancy-pattern/state/AR/index.html
build/my-fancy-pattern/state/AZ/index.html
build/my-fancy-pattern/state/CA/index.html
build/my-fancy-pattern/state/CO/index.html
... etc ...
Building JSON instead of HTML¶
Suppose you have a view the acts like an API, generating a small snippet of JSON. In this case, the official Django documentation recommends the following usage of class-based views to render the page in a dynamic website.
import json
from django.http import HttpResponse
from django.views.generic import TemplateView
class JSONResponseMixin(object):
"""
A mixin that can be used to render a JSON response.
"""
def render_to_json_response(self, context, **response_kwargs):
"""
Returns a JSON response, transforming 'context' to make the payload.
"""
return HttpResponse(
self.convert_context_to_json(context),
content_type='application/json',
**response_kwargs
)
def convert_context_to_json(self, context):
"Convert the context dictionary into a JSON object"
# Note: This is *EXTREMELY* naive; in reality, you'll need
# to do much more complex handling to ensure that arbitrary
# objects -- such as Django model instances or querysets
# -- can be serialized as JSON.
return json.dumps(context)
class JSONView(JSONResponseMixin, TemplateView):
def render_to_response(self, context, **response_kwargs):
return self.render_to_json_response(context, **response_kwargs)
def get_context_data(self, **kwargs):
return {'this-is': 'dummy-data'}
The same design pattern can work with django-bakery to build a flat version of the JSON response. All that’s necessary is to substitute a buildable view with some additional configuration.
import json
from django.http import HttpResponse
from bakery.views import BuildableTemplateView
class JSONResponseMixin(object):
"""
A mixin that can be used to render a JSON response.
"""
def render_to_json_response(self, context, **response_kwargs):
"""
Returns a JSON response, transforming 'context' to make the payload.
"""
return HttpResponse(
self.convert_context_to_json(context),
content_type='application/json',
**response_kwargs
)
def convert_context_to_json(self, context):
"Convert the context dictionary into a JSON object"
# Note: This is *EXTREMELY* naive; in reality, you'll need
# to do much more complex handling to ensure that arbitrary
# objects -- such as Django model instances or querysets
# -- can be serialized as JSON.
return json.dumps(context)
class BuildableJSONView(JSONResponseMixin, BuildableTemplateView):
# Nothing more than standard bakery configuration here
build_path = 'jsonview.json'
def render_to_response(self, context, **response_kwargs):
return self.render_to_json_response(context, **response_kwargs)
def get_context_data(self, **kwargs):
return {'this-is': 'dummy-data'}
def get_content(self):
"""
Overrides an internal trick of buildable views so that bakery
can render the HttpResponse substituted above for the typical Django
template by the JSONResponseMixin
"""
return self.get(self.request).content
Building a single view on demand¶
The build
management command can regenerate all pages for all views in the
BAKERY_VIEWS
settings variable. A buildable model
can recreate all pages related to a single object. But can you rebuild all pages
created by just one view? Yes, and all it takes is importing the view and invoking
its build_method
.
>>> from yourapp.views import DummyDetailView
>>> DummyDetailView().build_method()
A simple way to automate that kind of targeted build might be to create a custom management command and connect it to a cron job.
from django.core.management.base import BaseCommand, CommandError
from yourapp.views import DummyDetailView
class Command(BaseCommand):
help = 'Rebuilds all pages created by the DummyDetailView'
def handle(self, *args, **options):
DummyDetailView().build_method()
Or, if you wanted to rebuild the view without deleting everything else in the existing
build directory, you could pass it as an argument to the standard build
command
with instructions to skip everything else it normally does.
$ python manage.py build yourapp.views.DummyDetailView --keep-build-dir --skip-static --skip-media
Enabling Amazon’s accelerated uploads¶
If your bucket has enabled Amazon’s S3 transfer acceleration service,
you can configure bakery it use by overriding the default AWS_S3_HOST
variable in settings.py
.
AWS_S3_HOST = 's3-accelerate.amazonaws.com'