Skip to content

Instantly share code, notes, and snippets.

@kaedroho
Created January 11, 2018 14:14
Show Gist options
  • Save kaedroho/e96a5b7b651dc14a3a07d362ac448f07 to your computer and use it in GitHub Desktop.
Save kaedroho/e96a5b7b651dc14a3a07d362ac448f07 to your computer and use it in GitHub Desktop.
import logging
import os
from bakery.views import BuildableMixin
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from wagtail.wagtailcore.models import Page, Site
from wagtail.api.v2.endpoints import PagesAPIEndpoint
from wagtail.api.v2.router import WagtailAPIRouter
from wagtail.api.v2.pagination import WagtailPagination
logger = logging.getLogger(__name__)
class AllResultsWagtailPagination(WagtailPagination):
"""
A pagination class that returns all results on a single page
"""
def paginate_queryset(self, queryset, request, view=None):
self.view = view
self.total_count = queryset.count()
return queryset
class APIListingView(BuildableMixin):
@property
def build_method(self):
return self.build_queryset
def get_build_path(self):
target_path = os.path.join(settings.BUILD_DIR, self.build_path.lstrip('/'))
if not self.fs.exists(os.path.dirname(target_path)):
logger.debug("Creating {}".format(os.path.dirname(target_path)))
self.fs.makedirs(os.path.dirname(target_path))
return target_path
def build_queryset(self):
logger.debug("Building %s" % self.build_path)
self.request = self.create_request(self.build_path)
target_path = os.path.join(settings.BUILD_DIR, self.get_build_path())
self.build_file(target_path, self.get_content())
class APIDetailView(BuildableMixin):
"""
Render and build a "detail" view of an object.
Required attributes:
queryset:
the model instance the objects are looked up from.
"""
@property
def build_method(self):
return self.build_queryset
def get_url(self, obj):
"""
The URL at which the detail page should appear.
"""
if not hasattr(obj, 'get_absolute_url') or not obj.get_absolute_url():
raise ImproperlyConfigured("No URL configured. You must either \
set a ``get_absolute_url`` method on the %s model or override the %s view's \
``get_url`` method" % (obj.__class__.__name__, self.__class__.__name__))
return obj.get_absolute_url()
def get_build_path(self, obj):
"""
Used to determine where to build the detail page. Override this if you
would like your detail page at a different location. By default it
will be built at get_url()
"""
target_path = os.path.join(settings.BUILD_DIR, self.get_url(obj).lstrip('/'))
if not self.fs.exists(os.path.dirname(target_path)):
logger.debug("Creating {}".format(os.path.dirname(target_path)))
self.fs.makedirs(os.path.dirname(target_path))
return target_path
def set_kwargs(self, obj):
self.kwargs = {
'pk': getattr(obj, 'pk', None),
}
def build_object(self, obj):
logger.debug("Building %s" % obj)
self.request = self.create_request(self.get_url(obj))
self.set_kwargs(obj)
target_path = self.get_build_path(obj)
self.build_file(target_path, self.get_content())
def build_queryset(self):
[self.build_object(o) for o in self.get_queryset().all()]
def unbuild_object(self, obj):
"""
Deletes the file at self.get_build_path.
"""
logger.debug("Unbuilding %s" % obj)
target_path = os.path.split(self.get_build_path(obj))[0]
if self.fs.exists(target_path):
logger.debug("Removing {}".format(target_path))
self.fs.removetree(target_path)
def get_content(self):
# Create a dummy request
request = self.create_request('/?format=json&fields=*')
request.site = Site.objects.get(is_default_site=True)
request.wagtailapi_router = WagtailAPIRouter('')
response = PagesAPIEndpointWithoutPagination.as_view({'get': 'detail_view'})(request, pk=self.kwargs['pk'])
return response.render().content
class PagesAPIEndpointWithoutPagination(PagesAPIEndpoint):
pagination_class = AllResultsWagtailPagination
class PagesAPIDetailView(APIDetailView):
"""
Builds detail documents for every published page.
URL example: /api/pages/detail/1.json
"""
endpoint_class = PagesAPIEndpointWithoutPagination
def get_url(self, page):
return '/api/pages/detail/{}.json'.format(page.id)
def get_queryset(self):
if getattr(settings, 'BAKERY_MULTISITE', False):
return Page.objects.all().public().live()
else:
site = Site.objects.get(is_default_site=True)
return site.root_page.get_descendants(inclusive=True).public().live()
class PagesAPIListingView(APIListingView):
"""
Builds a single listing that lists every published page.
URL example: /api/pages/all.json
"""
build_path = '/api/pages/all.json'
def get_url(self):
return self.build_path
def fetch_page_listing(self, page_model=None):
if page_model:
url = '/?format=json&fields=*&type={}.{}'.format(page_model._meta.app_label, page_model.__name__)
else:
url = '/?format=json&fields=*'
request = self.create_request(url)
request.site = Site.objects.get(is_default_site=True)
request.wagtailapi_router = WagtailAPIRouter('')
response = PagesAPIEndpointWithoutPagination.as_view({'get': 'listing_view'})(request)
return response.render().content
def get_content(self):
return self.fetch_page_listing()
class TypedPagesAPIListingView(PagesAPIListingView):
"""
Builds a listing for each page type. Containing all published
pages of that type.
URL example: /api/pages/blog_BlogPage.json
"""
build_path = '/api/pages/{app_label}_{class_name}.json'
def get_url(self, cls):
return self.build_path.format(
app_label=cls._meta.app_label,
class_name=cls.__name__,
)
def get_content(self):
return self.fetch_page_listing(self.kwargs['cls'])
def set_kwargs(self, cls):
self.kwargs = {
'cls': cls,
}
def get_build_path(self, cls):
target_path = os.path.join(settings.BUILD_DIR, self.get_url(cls).lstrip('/'))
if not self.fs.exists(os.path.dirname(target_path)):
logger.debug("Creating {}".format(os.path.dirname(target_path)))
self.fs.makedirs(os.path.dirname(target_path))
return target_path
def build_page_type(self, cls):
logger.debug("Building %s" % cls)
self.request = self.create_request(self.get_url(cls))
self.set_kwargs(cls)
target_path = self.get_build_path(cls)
self.build_file(target_path, self.get_content())
def get_page_types(self):
return [
content_type.model_class()
for content_type in ContentType.objects.filter(id__in=Page.objects.values_list('content_type_id', flat=True))
]
def build(self):
for page_type in self.get_page_types():
self.build_page_type(page_type)
@property
def build_method(self):
return self.build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment