From 01c4280b72731a1f057455e13ed7720187763dd0 Mon Sep 17 00:00:00 2001 From: bkfox Date: Mon, 13 Jun 2016 04:25:17 +0200 Subject: [PATCH] redesign a bit view classes --- cms/sections.py | 7 +- cms/templates/aircox/cms/detail.html | 1 + cms/templates/aircox/cms/list.html | 3 +- cms/templates/aircox/cms/section.html | 8 +- cms/templates/aircox/cms/website.html | 22 +-- cms/views.py | 146 ++++++++++--------- cms/website.py | 104 +++++-------- liquidsoap/management/commands/liquidsoap.py | 37 ++--- programs/models.py | 1 - website/sections.py | 22 ++- 10 files changed, 176 insertions(+), 175 deletions(-) diff --git a/cms/sections.py b/cms/sections.py index bd44526..604a64c 100644 --- a/cms/sections.py +++ b/cms/sections.py @@ -79,7 +79,7 @@ class Section(Viewable, View): * force_object: (can be persistent) related object """ - template_name = 'aircox/cms/section.html' + template_name = 'aircox/cms/website.html' tag = 'div' name = '' @@ -132,6 +132,7 @@ class Section(Viewable, View): 'footer': self.footer, 'content': self.get_content(), 'object': self.object, + 'embed': True, } def render(self, request, object=None, context_only=False, **kwargs): @@ -140,6 +141,7 @@ class Section(Viewable, View): return context if not context: return '' + context['embed'] = True return render_to_string(self.template_name, context, request=request) @@ -239,6 +241,7 @@ class List(Section): * truncate: number of words to keep in content (0 = full content) """ template_name = 'aircox/cms/list.html' + base_template = 'aircox/cms/section.html' object_list = None url = None @@ -277,7 +280,7 @@ class List(Section): context = super().get_context_data(request, object, *args, **kwargs) context.update({ - 'base_template': 'aircox/cms/section.html', + 'base_template': self.base_template, 'list': self, 'object_list': object_list[:self.paginate_by] if object_list and self.paginate_by else diff --git a/cms/templates/aircox/cms/detail.html b/cms/templates/aircox/cms/detail.html index 08b0cd1..475b01d 100644 --- a/cms/templates/aircox/cms/detail.html +++ b/cms/templates/aircox/cms/detail.html @@ -1,4 +1,5 @@ {% extends "aircox/cms/website.html" %} + {% load aircox_cms %} {% block header %} diff --git a/cms/templates/aircox/cms/list.html b/cms/templates/aircox/cms/list.html index c60f5f1..f62975b 100644 --- a/cms/templates/aircox/cms/list.html +++ b/cms/templates/aircox/cms/list.html @@ -1,11 +1,10 @@ -{% extends base_template %} +{% extends "aircox/cms/website.html" %} {% load i18n %} {% load thumbnail %} {% load aircox_cms %} - {% block content %} {% endif %} -
+{% endif %} +{% if tag %} + <{{ tag }} {% if css_class %} class="{{ css_class }}" {% endif %} + {% for k, v in attrs.items %}{{ k }} = "{{ v|addslashes }}" + {% endfor %}> {% endif %} {% block title %} {% if title %} @@ -61,10 +62,9 @@ {% endif %} {% endblock %} -
- {% block content %} - {% endblock %} -
+ {% block content %} + {{ content|safe }} + {% endblock %} {% block footer %} {% if footer %} @@ -73,10 +73,10 @@ {% endif %} {% endblock %} - +{% if tag %} + +{% endif %} {% if not embed %} -
- {% if menus.right %} {{ menus.right|safe }} {% endif %} diff --git a/cms/views.py b/cms/views.py index b6db8d6..99df7fc 100644 --- a/cms/views.py +++ b/cms/views.py @@ -7,15 +7,23 @@ from django.contrib import messages from django.http import Http404 import aircox.cms.sections as sections +import aircox.cms.sections as sections_ -class PostBaseView: +class BaseView: """ - Base class for views. + Render a page using given sections. + + If sections is a list of sections, then render like a detail view; + If it is a single section, render it as website.html view; # Request GET params: * embed: view is embedded, render only the content of the view """ + template_name = '' + """it is set to "aircox/cms/detail.html" to render multiple sections""" + sections = None + """sections used to render the page""" website = None """website that uses the view""" menus = None @@ -27,6 +35,16 @@ class PostBaseView: css_class = '' # css classes for the HTML element of the content """css classes used for the HTML element containing the view""" + def __init__(self, sections = None, *args, **kwargs): + if hasattr(sections, '__iter__'): + self.sections = sections_.Sections(sections) + else: + self.sections = sections + super().__init__(*args, **kwargs) + + def __is_single(self): + return not issubclass(type(self.sections), list) + def add_css_class(self, css_class): """ Add the given class to the current class list if not yet present. @@ -37,32 +55,54 @@ class PostBaseView: else: self.css_class = css_class - def get_base_context(self, **kwargs): + def get_context_data(self, **kwargs): """ Return a context with all attributes of this classe plus 'view' set to self. """ - context = { - key: getattr(self, key) - for key in PostBaseView.__dict__.keys() - if not key.startswith('__') - } + context = super().get_context_data(**kwargs) + + # update from sections + if self.sections: + if self.__is_single(): + self.template_name = self.sections.template_name + context.update(self.sections.get_context_data( + self.request, **self.kwargs + ) or {}) + else: + if not self.template_name: + self.template_name = 'aircox/cms/detail.html' + context.update({ + 'content': self.sections.render(self.request, **kwargs) + }) + + # then from me + context.update({ + 'website': self.website, + 'view': self, + 'title': self.title, + 'tag': 'main', + 'attrs': self.attrs, + 'css_class': self.css_class, + }) if 'embed' not in self.request.GET: - object = self.object if hasattr(self, 'object') else None + if not kwargs.get('object'): + kwargs['object'] = self.object if hasattr(self, 'object') \ + else None if self.menus: context['menus'] = { - k: v.render(self.request, object = object, **kwargs) + k: v.render(self.request, **kwargs) for k, v in self.menus.items() + if v is not self } context['embed'] = False else: context['embed'] = True - context['view'] = self return context -class PostListView(PostBaseView, ListView): +class PostListView(BaseView, ListView): """ List view for posts and children. @@ -85,12 +125,16 @@ class PostListView(PostBaseView, ListView): route = None """route used to render this list""" - list = None - """list section to use to render the list and get base context. - By default it is sections.List""" - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + @property + def list(self): + """list section to use to render the list and get base context. + By default it is sections.List""" + return self.sections + + @list.setter + def list(self, value): + self.sections = value def dispatch(self, request, *args, **kwargs): self.route = self.kwargs.get('route') or self.route @@ -136,38 +180,27 @@ class PostListView(PostBaseView, ListView): self.init_list() self.add_css_class('list') - context = self.list.get_context_data(self.request, **self.kwargs) or {} - context.update(super().get_context_data(**kwargs)) - context.update(self.get_base_context(**kwargs)) + context = super().get_context_data(**kwargs) + # context.update(BaseView.get_context_data(self, **kwargs)) - if self.title: - title = self.title - elif self.route: - title = self.route.get_title(self.model, self.request, - **self.kwargs) + if not context.get('title') and self.route: + context['title'] = self.route.get_title( + self.model, self.request, **self.kwargs + ) - context.update({ - 'title': title, - 'base_template': 'aircox/cms/website.html', - 'css_class': self.css_class, - 'list': self.list, - }) + context['list'] = self.list return context -class PostDetailView(DetailView, PostBaseView): +class PostDetailView(BaseView, DetailView): """ Detail view for posts and children """ - template_name = 'aircox/cms/detail.html' - - sections = [] comments = None - def __init__(self, sections = None, *args, **kwargs): + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.add_css_class('detail') - self.sections = [ section() for section in (sections or []) ] def get_queryset(self): if self.model: @@ -183,17 +216,8 @@ class PostDetailView(DetailView, PostBaseView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context.update(self.get_base_context()) - - kwargs['object'] = self.object - context.update({ - 'title': self.title or self.object.title, - 'content': ''.join([ - section.render(request = self.request, **kwargs) - for section in self.sections - ]), - 'css_class': self.css_class, - }) + if not context.get('title'): + context['title'] = self.object.title return context def post(self, request, *args, **kwargs): @@ -210,27 +234,11 @@ class PostDetailView(DetailView, PostBaseView): return self.get(request, *args, **kwargs) -class PageView(TemplateView, PostBaseView): +class PageView(BaseView, TemplateView): """ - A simple page view. Used to render pages that have arbitrary content - without linked post object. + Render a page using given sections. + + If sections is a list of sections, then render like a detail view; + If it is a single section, render it as website.html view; """ - template_name = 'aircox/cms/detail.html' - - sections = [] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.sections = sections.Sections(self.sections) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context.update(self.get_base_context()) - context.update({ - 'title': self.title, - 'content': self.sections.render(request=self.request,**kwargs) - }) - return context - - diff --git a/cms/website.py b/cms/website.py index 982be35..ff7e63a 100644 --- a/cms/website.py +++ b/cms/website.py @@ -2,6 +2,7 @@ from django.utils.text import slugify from django.conf.urls import url import aircox.cms.routes as routes +import aircox.cms.routes as routes_ import aircox.cms.views as views import aircox.cms.models as models import aircox.cms.sections as sections @@ -66,9 +67,11 @@ class Website: Register routes for comments, for the moment, only ThreadRoute """ - self.register_list( - 'comment', models.Comment, + self.register( + 'comment', + view = views.PostListView, routes = [routes.ThreadRoute], + model = models.Comment, css_class = 'comments', list = sections.Comments( truncate = 30, @@ -76,7 +79,7 @@ class Website: ) ) - def register_model(self, name, model): + def __register_model(self, name, model): """ Register a model and return the name under which it is registered. Raise a ValueError if another model is yet associated under this name. @@ -90,82 +93,53 @@ class Website: model._website = self return name - def register_detail(self, name, model, view = views.PostDetailView, - **view_kwargs): + + def register(self, name, routes = [], view = views.PageView, + model = None, **view_kwargs): """ - Register a model and the detail view + Register a view using given name and routes. If model is given, + register the views for it. + + * name is used to register the routes as urls and the model if given + * routes: can be a path or a route used to generate urls for the view. + Can be a one item or a list of items. """ - name = self.register_model(name, model) + if model: + name = self.__register_model(name, model) + view_kwargs['model'] = model + if not view_kwargs.get('menus'): view_kwargs['menus'] = self.menus - - view = view.as_view( - website = self, - model = model, - **view_kwargs - ) - - self.urls.append(routes.DetailRoute.as_url(name, view)) - self.registry[name] = model - - def register_list(self, name, model, view = views.PostListView, - routes = [], **view_kwargs): - """ - Register a model and the given list view using the given routes - """ - name = self.register_model(name, model) - if not 'menus' in view_kwargs: - view_kwargs['menus'] = self.menus - - view = view.as_view( - website = self, - model = model, - **view_kwargs - ) - - self.urls += [ route.as_url(name, view) for route in routes ] - self.registry[name] = model - - def register_page(self, name, view = views.PageView, path = None, - **view_kwargs): - """ - Register a page that is accessible to the given path. If path is None, - use a slug of the name. - """ - if not 'menus' in view_kwargs: - view_kwargs['menus'] = self.menus - view = view.as_view( website = self, **view_kwargs ) - self.urls.append(url( - slugify(name) if path is None else path, - view = view, - name = name, - )) - def register(self, name, model, sections = None, routes = None, - list_view = views.PostListView, - detail_view = views.PostDetailView, - list_kwargs = {}, detail_kwargs = {}): + if type(routes) not in (tuple, list): + routes = [ routes ] + + self.urls += [ + route.as_url(name, view) + if type(route) == type and issubclass(route, routes_.Route) + else url(slugify(name) if not route else route, + view = view, name = name) + for route in routes + ] + + def register_post(self, name, model, sections = None, routes = None, + list_view = views.PostListView, + detail_view = views.PostDetailView, + list_kwargs = {}, detail_kwargs = {}): """ Register a detail and list view for a given model, using - routes. Just a wrapper around register_detail and - register_list. + routes. Just a wrapper around register. """ if sections: - self.register_detail( - name, model, - sections = sections, - **detail_kwargs - ) + self.register(name, [ routes_.DetailRoute ], view = detail_view, + model = model, sections = sections, **detail_kwargs) if routes: - self.register_list( - name, model, - routes = routes, - **list_kwargs - ) + self.register(name, routes, view = list_view, + model = model, **list_kwargs) def set_menu(self, menu): """ diff --git a/liquidsoap/management/commands/liquidsoap.py b/liquidsoap/management/commands/liquidsoap.py index 17a9a4b..add2512 100644 --- a/liquidsoap/management/commands/liquidsoap.py +++ b/liquidsoap/management/commands/liquidsoap.py @@ -169,6 +169,11 @@ class Command (BaseCommand): '-e', '--exec', action='store_true', help='run liquidsoap on exit' ) + group.add_argument( + '-s', '--station', type=str, + default = 'aircox', + help='use this name as station name (default is "aircox")' + ) group = parser.add_argument_group('actions') group.add_argument( @@ -194,12 +199,6 @@ class Command (BaseCommand): help='write configuration and playlist' ) - group.add_argument( - '-s', '--station', type=str, - default = 'aircox', - help='use this name as station name (default is "aircox")' - ) - def handle (self, *args, **options): run = options.get('run') monitor = options.get('on_air') or options.get('monitor') @@ -222,33 +221,27 @@ class Command (BaseCommand): controller.process.wait() def handle_write (self): - for controller in self.controllers: - controller.write() + self.controller.write() def handle_run (self): - for controller in self.controllers: - controller.process = \ - subprocess.Popen(['liquidsoap', '-v', controller.config_path], - stderr=subprocess.STDOUT) - atexit.register(controller.process.terminate) + self.controller.process = \ + subprocess.Popen( + ['liquidsoap', '-v', self.controller.config_path], + stderr=subprocess.STDOUT + ) + atexit.register(self.controller.process.terminate) def handle_monitor (self, options): - for controller in self.controllers: - controller.update() + self.controller.update() if options.get('on_air'): - for controller in self.controllers: - print(controller.id, controller.on_air) + print(self.controller.id, self.controller.on_air) return if options.get('monitor'): delay = options.get('delay') / 1000 while True: - for controller in self.controllers: - #try: - Monitor.run(controller) - #except Exception as err: - # print(err) + Monitor.run(self.controller) time.sleep(delay) return diff --git a/programs/models.py b/programs/models.py index 1ae6a10..da2be06 100755 --- a/programs/models.py +++ b/programs/models.py @@ -694,7 +694,6 @@ class Log(models.Model): 'related_type', 'related_id', ) - @classmethod def get_for_related_model(cl, model): """ diff --git a/website/sections.py b/website/sections.py index 4341f67..21ea34a 100644 --- a/website/sections.py +++ b/website/sections.py @@ -20,17 +20,37 @@ class Player(sections.Section): """ #default_sounds + @staticmethod + def on_air(): + """ + View that return what is on air formatted in JSON. + """ + qs = programs.Diffusion.get( + now = True, + type = programs.Diffusion.Type.normal + ) + + if not qs or not qs[0].is_date_in_my_range(): + return None + + qs = qs[0] + post = models.Diffusion.objects.filter(related = qs) + if not post: + post = models.Program.objects.filter(related = qs.program) + if not post: + post = ListItem(title = qs.program.name) + return post def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) context.update({ + 'base_template': 'aircox/cms/section.html', 'live_streams': self.live_streams }) return context - class Diffusions(sections.List): """ Section that print diffusions. When rendering, if there is no post yet