forked from rc/aircox
		
	viewset, detailview and sections
This commit is contained in:
		@ -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',
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										113
									
								
								website/views.py
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								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) ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user