diff --git a/website/models.py b/website/models.py index 959ed89..48142c9 100644 --- a/website/models.py +++ b/website/models.py @@ -137,11 +137,12 @@ class Article (BasePost): verbose_name_plural = _('Articles') - ProgramPost = Post.create_related_post(programs.Program, { 'title': 'name', 'content': 'description', }) + + EpisodePost = Post.create_related_post(programs.Episode, { 'title': 'name', 'content': 'description', diff --git a/website/routes.py b/website/routes.py index 3602d52..57f72a4 100644 --- a/website/routes.py +++ b/website/routes.py @@ -2,22 +2,24 @@ from django.conf.urls import url from django.utils import timezone from website.models import * +from website.views import * -class Routes: +class Router: registry = [] def register (self, route): if not route in self.registry: self.registry.append(route) + def register_set (self, view_set): + for route in view_set.routes: + self.register(route) + def unregister (self, route): self.registry.remove(route) def get_urlpatterns (self): - patterns = [] - for route in self.registry: - patterns += route.get_urlpatterns() or [] - return patterns + return [ route.get_url() for route in self.registry ] class Route: @@ -62,12 +64,16 @@ class Route: """ Called by the view to get the queryset when it is needed """ + pass - def get_urlpatterns (self): - view_kwargs = self.view_kwargs or {} + def get (self, request, **kwargs): + """ + Called by the view to get the object when it is needed + """ + pass + def get_url (self): pattern = '^{}/{}'.format(self.base_name, self.Meta.name) - if self._meta['url_args']: url_args = '/'.join([ '(?P<{}>{})'.format(arg, expr) \ for arg, expr in self._meta['url_args'] @@ -75,32 +81,26 @@ class Route: pattern += '/' + url_args pattern += '/?$' - return [ url( - pattern, - self.view and self.view.as_view( - route = self, - model = self.model, - **view_kwargs - ), - name = '{}' - ) ] + kwargs = { + 'route': self, + } + if self.view_kwargs: + kwargs.update(self.view_kwargs) + + return url(pattern, self.view, kwargs = kwargs, name = '{}') -class SearchRoute (Route): +class DetailRoute (Route): class Meta: - name = 'search' - is_list = True + name = 'detail' + is_list = False + url_args = [ + ('pk', '[0-9]+'), + ('slug', '(\w|-|_)*'), + ] - def get_queryset (self, request, **kwargs): - q = request.GET.get('q') or '' - qs = self.model.objects - for search_field in model.search_fields or []: - r = self.model.objects.filter(**{ search_field + '__icontains': q }) - if qs: qs = qs | r - else: qs = r - - qs.distinct() - return qs + def get (self, request, **kwargs): + return self.model.objects.get(pk = int(kwargs['pk'])) class ThreadRoute (Route): @@ -112,7 +112,7 @@ class ThreadRoute (Route): ] def get_queryset (self, request, **kwargs): - return self.model.objects.filter(thread__id = int(kwargs['pk'])) + return self.model.objects.filter(thread__pk = int(kwargs['pk'])) class DateRoute (Route): @@ -133,4 +133,21 @@ class DateRoute (Route): ) +class SearchRoute (Route): + class Meta: + name = 'search' + is_list = True + + def get_queryset (self, request, **kwargs): + q = request.GET.get('q') or '' + qs = self.model.objects + for search_field in model.search_fields or []: + r = self.model.objects.filter(**{ search_field + '__icontains': q }) + if qs: qs = qs | r + else: qs = r + + qs.distinct() + return qs + + diff --git a/website/templates/website/list.html b/website/templates/website/list.html index d75b077..d5293c3 100644 --- a/website/templates/website/list.html +++ b/website/templates/website/list.html @@ -1,9 +1,3 @@ -{# Parameters are: #} -{# * pub: publication itself; pub.meta must have been eval() #} -{# * threads: list of parent, from top to bottom, including itself #} -{# #} -{# * views: a view object used to know which view to use for links #} -{# #} {# {% extends embed|yesno:"website/single.html,website/base.html" %} #} {% load i18n %} @@ -11,6 +5,7 @@ {# {% load website_views %} #} +{% block content %}
{% for post in object_list %} {% endfor %}
+{% endblock %} diff --git a/website/urls.py b/website/urls.py index 7346238..70c944a 100644 --- a/website/urls.py +++ b/website/urls.py @@ -5,20 +5,42 @@ from website.views import * from website.routes import * -routes = Routes() +class ProgramSet (ViewSet): + model = ProgramPost + name = 'programs' -routes.register( SearchRoute(Article, PostListView) ) -routes.register( SearchRoute(ProgramPost, PostListView, base_name = 'programs') ) -#routes.register( SearchRoute(EpisodePost, PostListView, base_name = 'episodes') ) - -routes.register( ThreadRoute(Article, PostListView) ) -routes.register( ThreadRoute(ProgramPost, PostListView, base_name = 'programs') ) -#routes.register( ThreadRoute(EpisodePost, PostListView, base_name = 'episodes') ) - -routes.register( DateRoute(Article, PostListView) ) -routes.register( DateRoute(ProgramPost, PostListView, base_name = 'programs') ) -#routes.register( DateRoute(EpisodePost, PostListView, base_name = 'episodes') ) - -urlpatterns = routes.get_urlpatterns() + list_routes = [ + ThreadRoute, + SearchRoute, + DateRoute, + ] + + +class EpisodeSet (ViewSet): + model = EpisodePost + name = 'episodes' + + list_routes = [ + ThreadRoute, + SearchRoute, + DateRoute, + ] + + +class ArticleSet (ViewSet): + model = Article + list_routes = [ + ThreadRoute, + SearchRoute, + DateRoute, + ] + + +router = Router() +router.register_set(ProgramSet()) +router.register_set(EpisodeSet()) +router.register_set(ArticleSet()) + +urlpatterns = router.get_urlpatterns() diff --git a/website/utils.py b/website/utils.py deleted file mode 100644 index a31590c..0000000 --- a/website/utils.py +++ /dev/null @@ -1,83 +0,0 @@ -from django.db import models -from django.utils import timezone, dateformat -from programs.models import * - - -class ListQueries: - @staticmethod - def search (qs, q): - qs = qs.filter(tags__slug__in = re.compile(r'(\s|\+)+').split(q)) | \ - qs.filter(title__icontains = q) | \ - qs.filter(subtitle__icontains = q) | \ - qs.filter(content__icontains = q) - qs.distinct() - return qs - - @staticmethod - def thread (qs, q): - return qs.filter(parent = q) - - @staticmethod - def next (qs, q): - qs = qs.filter(date__gte = timezone.now()) - if q: - qs = qs.filter(parent = q) - return qs - - @staticmethod - def prev (qs, q): - qs = qs.filter(date__lte = timezone.now()) - if q: - qs = qs.filter(parent = q) - return qs - - @staticmethod - def date (qs, q): - if not q: - q = timezone.datetime.today() - if type(q) is str: - q = timezone.datetime.strptime(q, '%Y%m%d').date() - - return qs.filter(date__startswith = q) - - class Diffusion: - @staticmethod - def episode (qs, q): - return qs.filter(episode = q) - - @staticmethod - def program (qs, q): - return qs.filter(program = q) - -class ListQuery: - model = None - qs = None - - def __init__ (self, model, *kwargs): - self.model = model - self.__dict__.update(kwargs) - - def get_queryset (self, by, q): - qs = model.objects.all() - if model._meta.get_field_by_name('public'): - qs = qs.filter(public = True) - - # run query set - queries = Queries.__dict__.get(self.model) or Queries - filter = queries.__dict__.get(by) - if filter: - qs = filter(qs, q) - - # order - if self.sort == 'asc': - qs = qs.order_by('date', 'id') - else: - qs = qs.order_by('-date', '-id') - - # exclude - qs = qs.exclude(id = exclude) - - self.qs = qs - return qs - - diff --git a/website/views.py b/website/views.py index 2c2f93b..f8ae946 100644 --- a/website/views.py +++ b/website/views.py @@ -1,14 +1,18 @@ from django.shortcuts import render -from django.utils import timezone +from django.template.loader import render_to_string from django.views.generic import ListView from django.views.generic import DetailView from django.core import serializers from django.utils.translation import ugettext as _, ugettext_lazy from website.models import * +from website.routes import * class PostListView (ListView): + """ + List view for posts and children + """ class Query: """ Request availables parameters @@ -32,19 +36,18 @@ class PostListView (ListView): template_name = 'website/list.html' allow_empty = True + model = None query = None fields = [ 'date', 'time', 'image', 'title', 'content' ] - route = None - model = None - def __init__ (self, *args, **kwargs): - super(PostListView, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.query: self.query = Query(self.query) def get_queryset (self): - qs = self.route.get_queryset(self.request, **self.kwargs) + route = self.kwargs['route'] + qs = route.get_queryset(self.request, **self.kwargs) qs = qs.filter(public = True) query = self.query or PostListView.Query(self.request.GET) @@ -59,7 +62,7 @@ class PostListView (ListView): def get_context_data (self, **kwargs): - context = super(PostListView, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) context.update({ 'list': self }) @@ -67,4 +70,100 @@ class PostListView (ListView): return context +class PostDetailView (DetailView): + """ + Detail view for posts and children + """ + template_name = 'website/detail.html' + sections = None + + def __init__ (self, sections = None, *args, **kwargs): + super().__init__(*args, **kwargs) + + def get_queryset (self, **kwargs): + if self.model: + return super().get_queryset(**kwargs).filter(public = True) + return [] + + def get_object (self, **kwargs): + if self.model: + object = super().get_object(**kwargs) + if object.public: + return object + return None + + def get_context_data (self, **kwargs): + context = super().get_context_data(**kwargs) + context.update({ + 'sections': [ + section.get(self, self.request, object = self.object) + for section in self.sections + ] + }) + return context + + +class Section (DetailView): + """ + Base class for sections. Sections are view that can be used in detail view + in order to have extra content about a post. + """ + model = None + template_name = 'website/section.html' + classes = '' + title = '' + header = '' + bottom = '' + + def get_context_data (self, **kwargs): + context = super().get_context_date(**kwargs) + context.update({ + 'title': self.title, + 'header': self.header, + 'bottom': self.bottom, + 'classes': self.classes, + }) + + def get (self, request, **kwargs): + self.object = kwargs.get('object') + context = self.get_context_data(**kwargs) + return render_to_string(self.template_name, context) + + +class ViewSet: + """ + A ViewSet is a class helper that groups detail and list views that can be + used to generate views and routes given a model and a name used for the + routing. + """ + model = None + name = '' + + list_view = PostListView + list_routes = [] + + detail_view = PostDetailView + detail_sections = [] + + def __init__ (self): + if not self.name: + self.name = self.model._meta.verbose_name_plural + + self.detail_sections = [ + section.as_view(model = self.model) + for section in self.detail_sections + ] + self.detail_view = self.detail_view.as_view( + model = self.model, + sections = self.detail_sections + ) + self.list_view = self.list_view.as_view( + model = self.model + ) + + self.routes = [ route(self.model, self.list_view, base_name = self.name) + for route in self.list_routes ] + \ + [ DetailRoute(self.model, self.detail_view, + base_name = self.name) ] +