viewset, detailview and sections

This commit is contained in:
bkfox 2015-09-30 14:19:36 +02:00
parent 6dd2036ec9
commit 8d561a1f7b
6 changed files with 194 additions and 142 deletions

View File

@ -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',

View File

@ -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

View File

@ -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 %}
<div class="post_list {{ classes }}">
{% for post in object_list %}
<a class="post_item"
@ -47,5 +42,6 @@
</a>
{% endfor %}
</div>
{% endblock %}

View File

@ -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()

View File

@ -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

View File

@ -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) ]