redesign a bit view classes

This commit is contained in:
bkfox 2016-06-13 04:25:17 +02:00
parent c3ae0e012c
commit 01c4280b72
10 changed files with 176 additions and 175 deletions

View File

@ -79,7 +79,7 @@ class Section(Viewable, View):
* force_object: (can be persistent) related object * force_object: (can be persistent) related object
""" """
template_name = 'aircox/cms/section.html' template_name = 'aircox/cms/website.html'
tag = 'div' tag = 'div'
name = '' name = ''
@ -132,6 +132,7 @@ class Section(Viewable, View):
'footer': self.footer, 'footer': self.footer,
'content': self.get_content(), 'content': self.get_content(),
'object': self.object, 'object': self.object,
'embed': True,
} }
def render(self, request, object=None, context_only=False, **kwargs): def render(self, request, object=None, context_only=False, **kwargs):
@ -140,6 +141,7 @@ class Section(Viewable, View):
return context return context
if not context: if not context:
return '' return ''
context['embed'] = True
return render_to_string(self.template_name, context, request=request) 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) * truncate: number of words to keep in content (0 = full content)
""" """
template_name = 'aircox/cms/list.html' template_name = 'aircox/cms/list.html'
base_template = 'aircox/cms/section.html'
object_list = None object_list = None
url = None url = None
@ -277,7 +280,7 @@ class List(Section):
context = super().get_context_data(request, object, *args, **kwargs) context = super().get_context_data(request, object, *args, **kwargs)
context.update({ context.update({
'base_template': 'aircox/cms/section.html', 'base_template': self.base_template,
'list': self, 'list': self,
'object_list': object_list[:self.paginate_by] 'object_list': object_list[:self.paginate_by]
if object_list and self.paginate_by else if object_list and self.paginate_by else

View File

@ -1,4 +1,5 @@
{% extends "aircox/cms/website.html" %} {% extends "aircox/cms/website.html" %}
{% load aircox_cms %} {% load aircox_cms %}
{% block header %} {% block header %}

View File

@ -1,11 +1,10 @@
{% extends base_template %} {% extends "aircox/cms/website.html" %}
{% load i18n %} {% load i18n %}
{% load thumbnail %} {% load thumbnail %}
{% load aircox_cms %} {% load aircox_cms %}
{% block content %} {% block content %}
<ul class="content"> <ul class="content">
{% for item in object_list %} {% for item in object_list %}

View File

@ -1,8 +1,9 @@
{% if tag %}
<{{ tag }} {% if css_class %} class="{{ css_class }}" {% endif %} <{{ tag }} {% if css_class %} class="{{ css_class }}" {% endif %}
{% for k, v in attrs.items %} {% for k, v in attrs.items %}
{{ k }} = "{{ v|addslashes }}" {{ k }} = "{{ v|addslashes }}"
{% endfor %} > {% endfor %} >
{% endif %}
{% block title %} {% block title %}
{% if title %} {% if title %}
@ -29,5 +30,8 @@
</footer> </footer>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
</{{ tag }}>
{% if tag %}
</{{ tag }}>
{% endif %}

View File

@ -42,10 +42,11 @@
</ul> </ul>
{% endif %} {% endif %}
<main {% if css_class %} class="{{ css_class }}" {% endif %} {% endif %}
{% for k, v in attrs.items %} {% if tag %}
{{ k }} = "{{ v|addslashes }}" <{{ tag }} {% if css_class %} class="{{ css_class }}" {% endif %}
{% endfor %} > {% for k, v in attrs.items %}{{ k }} = "{{ v|addslashes }}"
{% endfor %}>
{% endif %} {% endif %}
{% block title %} {% block title %}
{% if title %} {% if title %}
@ -61,10 +62,9 @@
{% endif %} {% endif %}
{% endblock %} {% endblock %}
<div class="content">
{% block content %} {% block content %}
{{ content|safe }}
{% endblock %} {% endblock %}
</div>
{% block footer %} {% block footer %}
{% if footer %} {% if footer %}
@ -73,10 +73,10 @@
</footer> </footer>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% if tag %}
</{{ tag }}>
{% endif %}
{% if not embed %} {% if not embed %}
</main>
{% if menus.right %} {% if menus.right %}
{{ menus.right|safe }} {{ menus.right|safe }}
{% endif %} {% endif %}

View File

@ -7,15 +7,23 @@ from django.contrib import messages
from django.http import Http404 from django.http import Http404
import aircox.cms.sections as sections 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: # Request GET params:
* embed: view is embedded, render only the content of the view * 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 = None
"""website that uses the view""" """website that uses the view"""
menus = None menus = None
@ -27,6 +35,16 @@ class PostBaseView:
css_class = '' # css classes for the HTML element of the content css_class = '' # css classes for the HTML element of the content
"""css classes used for the HTML element containing the view""" """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): def add_css_class(self, css_class):
""" """
Add the given class to the current class list if not yet present. Add the given class to the current class list if not yet present.
@ -37,32 +55,54 @@ class PostBaseView:
else: else:
self.css_class = css_class 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 Return a context with all attributes of this classe plus 'view' set
to self. to self.
""" """
context = { context = super().get_context_data(**kwargs)
key: getattr(self, key)
for key in PostBaseView.__dict__.keys() # update from sections
if not key.startswith('__') 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: 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: if self.menus:
context['menus'] = { context['menus'] = {
k: v.render(self.request, object = object, **kwargs) k: v.render(self.request, **kwargs)
for k, v in self.menus.items() for k, v in self.menus.items()
if v is not self
} }
context['embed'] = False context['embed'] = False
else: else:
context['embed'] = True context['embed'] = True
context['view'] = self
return context return context
class PostListView(PostBaseView, ListView): class PostListView(BaseView, ListView):
""" """
List view for posts and children. List view for posts and children.
@ -85,12 +125,16 @@ class PostListView(PostBaseView, ListView):
route = None route = None
"""route used to render this list""" """route used to render this list"""
list = None
@property
def list(self):
"""list section to use to render the list and get base context. """list section to use to render the list and get base context.
By default it is sections.List""" By default it is sections.List"""
return self.sections
def __init__(self, *args, **kwargs): @list.setter
super().__init__(*args, **kwargs) def list(self, value):
self.sections = value
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.route = self.kwargs.get('route') or self.route self.route = self.kwargs.get('route') or self.route
@ -136,38 +180,27 @@ class PostListView(PostBaseView, ListView):
self.init_list() self.init_list()
self.add_css_class('list') self.add_css_class('list')
context = self.list.get_context_data(self.request, **self.kwargs) or {} context = super().get_context_data(**kwargs)
context.update(super().get_context_data(**kwargs)) # context.update(BaseView.get_context_data(self, **kwargs))
context.update(self.get_base_context(**kwargs))
if self.title: if not context.get('title') and self.route:
title = self.title context['title'] = self.route.get_title(
elif self.route: self.model, self.request, **self.kwargs
title = self.route.get_title(self.model, self.request, )
**self.kwargs)
context.update({ context['list'] = self.list
'title': title,
'base_template': 'aircox/cms/website.html',
'css_class': self.css_class,
'list': self.list,
})
return context return context
class PostDetailView(DetailView, PostBaseView): class PostDetailView(BaseView, DetailView):
""" """
Detail view for posts and children Detail view for posts and children
""" """
template_name = 'aircox/cms/detail.html'
sections = []
comments = None comments = None
def __init__(self, sections = None, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.add_css_class('detail') self.add_css_class('detail')
self.sections = [ section() for section in (sections or []) ]
def get_queryset(self): def get_queryset(self):
if self.model: if self.model:
@ -183,17 +216,8 @@ class PostDetailView(DetailView, PostBaseView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context.update(self.get_base_context()) if not context.get('title'):
context['title'] = self.object.title
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,
})
return context return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@ -210,27 +234,11 @@ class PostDetailView(DetailView, PostBaseView):
return self.get(request, *args, **kwargs) 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 Render a page using given sections.
without linked post object.
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

View File

@ -2,6 +2,7 @@ from django.utils.text import slugify
from django.conf.urls import url from django.conf.urls import url
import aircox.cms.routes as routes import aircox.cms.routes as routes
import aircox.cms.routes as routes_
import aircox.cms.views as views import aircox.cms.views as views
import aircox.cms.models as models import aircox.cms.models as models
import aircox.cms.sections as sections import aircox.cms.sections as sections
@ -66,9 +67,11 @@ class Website:
Register routes for comments, for the moment, only Register routes for comments, for the moment, only
ThreadRoute ThreadRoute
""" """
self.register_list( self.register(
'comment', models.Comment, 'comment',
view = views.PostListView,
routes = [routes.ThreadRoute], routes = [routes.ThreadRoute],
model = models.Comment,
css_class = 'comments', css_class = 'comments',
list = sections.Comments( list = sections.Comments(
truncate = 30, 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. Register a model and return the name under which it is registered.
Raise a ValueError if another model is yet associated under this name. Raise a ValueError if another model is yet associated under this name.
@ -90,82 +93,53 @@ class Website:
model._website = self model._website = self
return name 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'): if not view_kwargs.get('menus'):
view_kwargs['menus'] = self.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( view = view.as_view(
website = self, website = self,
**view_kwargs **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, 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, list_view = views.PostListView,
detail_view = views.PostDetailView, detail_view = views.PostDetailView,
list_kwargs = {}, detail_kwargs = {}): list_kwargs = {}, detail_kwargs = {}):
""" """
Register a detail and list view for a given model, using Register a detail and list view for a given model, using
routes. Just a wrapper around register_detail and routes. Just a wrapper around register.
register_list.
""" """
if sections: if sections:
self.register_detail( self.register(name, [ routes_.DetailRoute ], view = detail_view,
name, model, model = model, sections = sections, **detail_kwargs)
sections = sections,
**detail_kwargs
)
if routes: if routes:
self.register_list( self.register(name, routes, view = list_view,
name, model, model = model, **list_kwargs)
routes = routes,
**list_kwargs
)
def set_menu(self, menu): def set_menu(self, menu):
""" """

View File

@ -169,6 +169,11 @@ class Command (BaseCommand):
'-e', '--exec', action='store_true', '-e', '--exec', action='store_true',
help='run liquidsoap on exit' 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 = parser.add_argument_group('actions')
group.add_argument( group.add_argument(
@ -194,12 +199,6 @@ class Command (BaseCommand):
help='write configuration and playlist' 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): def handle (self, *args, **options):
run = options.get('run') run = options.get('run')
monitor = options.get('on_air') or options.get('monitor') monitor = options.get('on_air') or options.get('monitor')
@ -222,33 +221,27 @@ class Command (BaseCommand):
controller.process.wait() controller.process.wait()
def handle_write (self): def handle_write (self):
for controller in self.controllers: self.controller.write()
controller.write()
def handle_run (self): def handle_run (self):
for controller in self.controllers: self.controller.process = \
controller.process = \ subprocess.Popen(
subprocess.Popen(['liquidsoap', '-v', controller.config_path], ['liquidsoap', '-v', self.controller.config_path],
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT
atexit.register(controller.process.terminate) )
atexit.register(self.controller.process.terminate)
def handle_monitor (self, options): def handle_monitor (self, options):
for controller in self.controllers: self.controller.update()
controller.update()
if options.get('on_air'): if options.get('on_air'):
for controller in self.controllers: print(self.controller.id, self.controller.on_air)
print(controller.id, controller.on_air)
return return
if options.get('monitor'): if options.get('monitor'):
delay = options.get('delay') / 1000 delay = options.get('delay') / 1000
while True: while True:
for controller in self.controllers: Monitor.run(self.controller)
#try:
Monitor.run(controller)
#except Exception as err:
# print(err)
time.sleep(delay) time.sleep(delay)
return return

View File

@ -694,7 +694,6 @@ class Log(models.Model):
'related_type', 'related_id', 'related_type', 'related_id',
) )
@classmethod @classmethod
def get_for_related_model(cl, model): def get_for_related_model(cl, model):
""" """

View File

@ -20,17 +20,37 @@ class Player(sections.Section):
""" """
#default_sounds #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): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
context.update({ context.update({
'base_template': 'aircox/cms/section.html',
'live_streams': self.live_streams 'live_streams': self.live_streams
}) })
return context return context
class Diffusions(sections.List): class Diffusions(sections.List):
""" """
Section that print diffusions. When rendering, if there is no post yet Section that print diffusions. When rendering, if there is no post yet