forked from rc/aircox
rewrite a bit how views and sections work; section's prepare function; website interfaces; section.as_view returns a view containing it and usable as it
This commit is contained in:
parent
32a30004d6
commit
4e5d90fb1d
|
@ -34,21 +34,21 @@ class Route:
|
|||
"""
|
||||
|
||||
@classmethod
|
||||
def get_queryset(cl, model, request, **kwargs):
|
||||
def get_queryset(cl, website, request, **kwargs):
|
||||
"""
|
||||
Called by the view to get the queryset when it is needed
|
||||
"""
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_object(cl, model, request, **kwargs):
|
||||
def get_object(cl, website, request, **kwargs):
|
||||
"""
|
||||
Called by the view to get the object when it is needed
|
||||
"""
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_title(cl, model, request, **kwargs):
|
||||
def get_title(cl, website, request, **kwargs):
|
||||
return ''
|
||||
|
||||
@classmethod
|
||||
|
@ -56,8 +56,12 @@ class Route:
|
|||
return name + '.' + cl.name
|
||||
|
||||
@classmethod
|
||||
def as_url(cl, name, view, view_kwargs = None):
|
||||
pattern = '^{}/{}'.format(name, cl.name)
|
||||
def make_pattern(cl, prefix = ''):
|
||||
"""
|
||||
Make a url pattern using prefix as prefix and cl.params as
|
||||
parameters.
|
||||
"""
|
||||
pattern = prefix
|
||||
if cl.params:
|
||||
pattern += ''.join([
|
||||
'{pre}/(?P<{name}>{regexp}){post}'.format(
|
||||
|
@ -68,13 +72,13 @@ class Route:
|
|||
for name, regexp, *optional in cl.params
|
||||
])
|
||||
pattern += '/?$'
|
||||
return pattern
|
||||
|
||||
kwargs = {
|
||||
'route': cl,
|
||||
}
|
||||
if view_kwargs:
|
||||
kwargs.update(view_kwargs)
|
||||
|
||||
@classmethod
|
||||
def as_url(cl, name, view, kwargs = None):
|
||||
pattern = cl.make_pattern('^{}/{}'.format(name, cl.name))
|
||||
kwargs = kwargs.copy() if kwargs else {}
|
||||
kwargs['route'] = cl
|
||||
return url(pattern, view, kwargs = kwargs,
|
||||
name = cl.make_view_name(name))
|
||||
|
||||
|
|
108
cms/sections.py
108
cms/sections.py
|
@ -29,20 +29,19 @@ class Viewable:
|
|||
@classmethod
|
||||
def as_view (cl, *args, **kwargs):
|
||||
"""
|
||||
Similar to View.as_view, but instead, wrap a constructor of the
|
||||
given class that is used as is.
|
||||
Create a view containing the current viewable, using a subclass
|
||||
of aircox.cms.views.BaseView.
|
||||
All the arguments are passed to the view directly.
|
||||
"""
|
||||
def func(**kwargs_):
|
||||
if kwargs_:
|
||||
kwargs.update(kwargs_)
|
||||
instance = cl(*args, **kwargs)
|
||||
return instance
|
||||
return func
|
||||
from aircox.cms.views import PageView
|
||||
kwargs['sections'] = cl
|
||||
return PageView.as_view(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def extends (cl, **kwargs):
|
||||
"""
|
||||
Return a sub class where the given attribute have been updated
|
||||
using kwargs.
|
||||
"""
|
||||
class Sub(cl):
|
||||
pass
|
||||
|
@ -60,13 +59,20 @@ class Sections(Viewable, list):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def prepare(self, *args, **kwargs):
|
||||
"""
|
||||
prepare all children sections
|
||||
"""
|
||||
for i, section in enumerate(self):
|
||||
if callable(section) or type(section) == type:
|
||||
self[i] = section()
|
||||
self[i].prepare(*args, **kwargs)
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
if args:
|
||||
self.prepare(*args, **kwargs)
|
||||
return ''.join([
|
||||
section.render(*args, **kwargs)
|
||||
section.render()
|
||||
for section in self
|
||||
])
|
||||
|
||||
|
@ -127,6 +133,7 @@ class Section(Viewable, View):
|
|||
its value is an empty string (prints an empty string).
|
||||
"""
|
||||
|
||||
view = None
|
||||
request = None
|
||||
object = None
|
||||
kwargs = None
|
||||
|
@ -138,8 +145,8 @@ class Section(Viewable, View):
|
|||
else:
|
||||
self.css_class = css_class
|
||||
|
||||
def __init__ (self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
def __init__ (self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.add_css_class('section')
|
||||
if type(self) != Section:
|
||||
|
@ -159,11 +166,7 @@ class Section(Viewable, View):
|
|||
"""
|
||||
return False
|
||||
|
||||
def get_context_data(self, request = None, object = None, **kwargs):
|
||||
if request: self.request = request
|
||||
if object: self.object = object
|
||||
if kwargs: self.kwargs = kwargs
|
||||
|
||||
def get_context_data(self):
|
||||
return {
|
||||
'view': self,
|
||||
'exp': (hasattr(self, '_exposure') and self._exposure) or None,
|
||||
|
@ -178,8 +181,24 @@ class Section(Viewable, View):
|
|||
'embed': True,
|
||||
}
|
||||
|
||||
def render(self, request, object=None, **kwargs):
|
||||
context = self.get_context_data(request=request, object=object, **kwargs)
|
||||
def prepare(self, view, **kwargs):
|
||||
"""
|
||||
initialize the object with valuable informations.
|
||||
"""
|
||||
self.view = view
|
||||
self.request = view.request
|
||||
self.kwargs = view.kwargs
|
||||
if hasattr(view, 'object'):
|
||||
self.object = view.object
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
"""
|
||||
Render the section as a string. Use *args and **kwargs to prepare
|
||||
the section, then get_context_data and render.
|
||||
"""
|
||||
if args and not self.view:
|
||||
self.prepare(*args, **kwargs)
|
||||
context = self.get_context_data()
|
||||
|
||||
is_empty = self.is_empty()
|
||||
if not context or (is_empty and not self.message_empty):
|
||||
|
@ -189,7 +208,9 @@ class Section(Viewable, View):
|
|||
context['content'] = self.message_empty
|
||||
|
||||
context['embed'] = True
|
||||
return render_to_string(self.template_name, context, request=request)
|
||||
return render_to_string(
|
||||
self.template_name, context, request=self.request
|
||||
)
|
||||
|
||||
|
||||
class Image(Section):
|
||||
|
@ -336,11 +357,17 @@ class List(Section):
|
|||
ListItem(item) for item in items
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def as_view(cl, *args, **kwargs):
|
||||
from aircox.cms.views import PostListView
|
||||
kwargs['sections'] = cl
|
||||
return PostListView.as_view(*args, **kwargs)
|
||||
|
||||
def is_empty(self):
|
||||
return not self.object_list
|
||||
|
||||
def get_object_list(self):
|
||||
return self.object_list
|
||||
return self.object_list or []
|
||||
|
||||
def prepare_list(self, object_list):
|
||||
"""
|
||||
|
@ -349,8 +376,7 @@ class List(Section):
|
|||
"""
|
||||
return object_list
|
||||
|
||||
def get_context_data(self, request, object=None, object_list=None,
|
||||
*args, **kwargs):
|
||||
def get_context_data(self, *args, object_list=None, **kwargs):
|
||||
"""
|
||||
Return a context that is passed to the template at rendering, with
|
||||
the following values:
|
||||
|
@ -364,21 +390,20 @@ class List(Section):
|
|||
|
||||
Set `request`, `object`, `object_list` and `kwargs` in self.
|
||||
"""
|
||||
if request: self.request = request
|
||||
if object: self.object = object
|
||||
if kwargs: self.kwargs = kwargs
|
||||
if args:
|
||||
self.prepare(*args, **kwargs)
|
||||
|
||||
if object_list is None:
|
||||
object_list = self.object_list or self.get_object_list()
|
||||
if not object_list and not self.message_empty:
|
||||
return
|
||||
return {}
|
||||
|
||||
self.object_list = object_list
|
||||
if object_list:
|
||||
object_list = self.prepare_list(object_list)
|
||||
Actions.make(request, object_list = object_list)
|
||||
Actions.make(self.request, object_list = object_list)
|
||||
|
||||
context = super().get_context_data(request, object, *args, **kwargs)
|
||||
context = super().get_context_data()
|
||||
context.update({
|
||||
'list': self,
|
||||
'object_list': object_list[:self.paginate_by]
|
||||
|
@ -510,13 +535,16 @@ class Menu(Section):
|
|||
if not self.attrs:
|
||||
self.attrs = {}
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
super().get_context_data(*args, **kwargs)
|
||||
def prepare(self, *args, **kwargs):
|
||||
super().prepare(*args, **kwargs)
|
||||
self.sections.prepare(*args, **kwargs)
|
||||
|
||||
def get_context_data(self):
|
||||
return {
|
||||
'tag': self.tag,
|
||||
'css_class': self.css_class,
|
||||
'attrs': self.attrs,
|
||||
'content': self.sections.render(*args, **kwargs)
|
||||
'content': self.sections.render()
|
||||
}
|
||||
|
||||
|
||||
|
@ -579,16 +607,18 @@ class Calendar(Section):
|
|||
date = date.replace(day = 1)
|
||||
|
||||
first, count = calendar.monthrange(date.year, date.month)
|
||||
def make_date(date, day):
|
||||
date += tz.timedelta(days=day)
|
||||
return (
|
||||
date, self.model.reverse(
|
||||
routes.DateRoute, year = date.year,
|
||||
month = date.month, day = date.day
|
||||
)
|
||||
)
|
||||
|
||||
context.update({
|
||||
'first_weekday': first,
|
||||
'days': [
|
||||
(date + tz.timedelta(days=day), self.model.reverse(
|
||||
routes.DateRoute, year = date.year, month = date.month,
|
||||
day = day
|
||||
)
|
||||
) for day in range(0, count)
|
||||
],
|
||||
|
||||
'days': [ make_date(date, day) for day in range(0, count) ],
|
||||
'today': datetime.date.today(),
|
||||
'this_month': date,
|
||||
'prev_month': date - tz.timedelta(days=10),
|
||||
|
|
44
cms/views.py
44
cms/views.py
|
@ -21,7 +21,7 @@ class BaseView:
|
|||
# Request GET params:
|
||||
* embed: view is embedded, render only the content of the view
|
||||
"""
|
||||
template_name = ''
|
||||
template_name = 'aircox/cms/website.html'
|
||||
"""it is set to "aircox/cms/detail.html" to render multiple sections"""
|
||||
sections = None
|
||||
"""sections used to render the page"""
|
||||
|
@ -43,9 +43,6 @@ class BaseView:
|
|||
self.sections = sections
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __section_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.
|
||||
|
@ -65,19 +62,15 @@ class BaseView:
|
|||
|
||||
# update from sections
|
||||
if self.sections:
|
||||
if self.__section_is_single():
|
||||
if issubclass(type(self.sections), sections.Section):
|
||||
self.template_name = self.sections.template_name
|
||||
context.update(self.sections.get_context_data(
|
||||
self.request,
|
||||
object_list = hasattr(self, 'object_list') and \
|
||||
self.object_list,
|
||||
**self.kwargs
|
||||
) or {})
|
||||
self.sections.prepare(self)
|
||||
context.update(self.sections.get_context_data())
|
||||
else:
|
||||
if not self.template_name:
|
||||
self.template_name = 'aircox/cms/detail.html'
|
||||
context.update({
|
||||
'content': self.sections.render(self.request, **kwargs)
|
||||
'content': self.sections.render(self)
|
||||
})
|
||||
|
||||
context.update(super().get_context_data(**kwargs))
|
||||
|
@ -98,7 +91,7 @@ class BaseView:
|
|||
else None
|
||||
if self.menus:
|
||||
context['menus'] = {
|
||||
k: v.render(self.request, **kwargs)
|
||||
k: v.render(self)
|
||||
for k, v in self.menus.items()
|
||||
if v is not self
|
||||
}
|
||||
|
@ -148,6 +141,12 @@ class PostListView(BaseView, ListView):
|
|||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
default = self.prepare_list()
|
||||
if default:
|
||||
qs = self.list.get_object_list()
|
||||
if qs:
|
||||
return qs
|
||||
|
||||
if self.route:
|
||||
qs = self.route.get_queryset(self.model, self.request,
|
||||
**self.kwargs)
|
||||
|
@ -166,15 +165,23 @@ class PostListView(BaseView, ListView):
|
|||
return qs
|
||||
|
||||
def prepare_list(self):
|
||||
"""
|
||||
Prepare the list and return True if the list has been created using
|
||||
defaults.
|
||||
"""
|
||||
if not self.list:
|
||||
self.list = sections.List(
|
||||
truncate = 32,
|
||||
paginate_by = 0,
|
||||
)
|
||||
else:
|
||||
default = True
|
||||
elif type(self.list) == type:
|
||||
self.list = self.list(paginate_by = 0)
|
||||
self.template_name = self.list.template_name
|
||||
self.css_class = self.list.css_class
|
||||
default = False
|
||||
|
||||
self.list.prepare(self)
|
||||
|
||||
if self.request.GET.get('fields'):
|
||||
self.list.fields = [
|
||||
|
@ -184,12 +191,14 @@ class PostListView(BaseView, ListView):
|
|||
|
||||
# done in list
|
||||
# Actions.make(self.request, object_list = self.object_list)
|
||||
return default
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
self.prepare_list()
|
||||
self.add_css_class('list')
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
if not context.get('object_list'):
|
||||
context['object_list'] = self.list.object_list
|
||||
|
||||
if self.route and not context.get('title'):
|
||||
context['title'] = self.route.get_title(
|
||||
|
@ -232,12 +241,14 @@ class PostDetailView(BaseView, DetailView):
|
|||
"""
|
||||
Handle new comments
|
||||
"""
|
||||
self.sections.prepare(self)
|
||||
if not self.comments:
|
||||
for section in self.sections:
|
||||
if issubclass(type(section), sections.Comments):
|
||||
self.comments = section
|
||||
|
||||
self.object = self.get_object()
|
||||
self.comments.prepare(self)
|
||||
self.comments.post(self, request, self.object)
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
|
@ -249,8 +260,5 @@ class PageView(BaseView, TemplateView):
|
|||
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;
|
||||
"""
|
||||
# dirty hack in order to accept a "model" kwargs, to allow "model=None"
|
||||
# in routes. Cf. website.register (at if model / else)
|
||||
model = None
|
||||
|
||||
|
||||
|
|
144
cms/website.py
144
cms/website.py
|
@ -9,6 +9,7 @@ import aircox.cms.routes as routes_
|
|||
import aircox.cms.views as views
|
||||
import aircox.cms.models as models
|
||||
import aircox.cms.sections as sections
|
||||
import aircox.cms.sections as sections_
|
||||
|
||||
|
||||
class Website:
|
||||
|
@ -37,7 +38,7 @@ class Website:
|
|||
|
||||
## components
|
||||
Registration = namedtuple('Registration',
|
||||
'name model routes as_default'
|
||||
'name model routes default'
|
||||
)
|
||||
|
||||
urls = []
|
||||
|
@ -64,7 +65,7 @@ class Website:
|
|||
if self.comments_routes:
|
||||
self.register_comments()
|
||||
|
||||
def register_model(self, name, model, as_default):
|
||||
def register_model(self, name, model, default):
|
||||
"""
|
||||
Register a model and update model's fields with few data:
|
||||
- _website: back ref to self
|
||||
|
@ -77,9 +78,9 @@ class Website:
|
|||
if reg.model is model:
|
||||
return reg
|
||||
raise ValueError('A model has yet been registered under "{}"'
|
||||
.format(name))
|
||||
.format(reg.model, name))
|
||||
|
||||
reg = self.Registration(name, model, [], as_default)
|
||||
reg = self.Registration(name, model, [], default)
|
||||
self.registry[name] = reg
|
||||
model._registration = reg
|
||||
model._website = self
|
||||
|
@ -97,74 +98,89 @@ class Website:
|
|||
continue
|
||||
self.exposures += section._exposure.gather(section)
|
||||
|
||||
def register(self, name, routes = [], view = views.PageView,
|
||||
model = None, sections = None,
|
||||
as_default = False, **view_kwargs):
|
||||
"""
|
||||
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.
|
||||
* view: route that is registered for the given routes
|
||||
* model: model being registrated. If given, register it in the website
|
||||
under the given name, and make it available to the view.
|
||||
* as_default: make the view available as a default view.
|
||||
"""
|
||||
if type(routes) not in (tuple, list):
|
||||
routes = [ routes ]
|
||||
|
||||
# model registration
|
||||
if model:
|
||||
reg = self.register_model(name, model, as_default)
|
||||
reg.routes.extend(routes)
|
||||
view_kwargs['model'] = model
|
||||
else:
|
||||
view_kwargs['model'] = None
|
||||
|
||||
# init view
|
||||
if not view_kwargs.get('menus'):
|
||||
view_kwargs['menus'] = self.menus
|
||||
|
||||
if sections:
|
||||
self.register_exposures(sections)
|
||||
view_kwargs['sections'] = sections
|
||||
|
||||
def __route_to_url(self, name, route, view, sections, kwargs):
|
||||
# route can be a tuple
|
||||
if type(route) in (tuple,list):
|
||||
route, view = route
|
||||
view = view.as_view(
|
||||
website = self,
|
||||
**view_kwargs
|
||||
website = self, **kwargs
|
||||
)
|
||||
|
||||
# url gen
|
||||
# route can be a route or a string
|
||||
if type(route) == type and issubclass(route, routes_.Route):
|
||||
return route.as_url(name, view)
|
||||
|
||||
return url(
|
||||
slugify(name) if not route else str(route),
|
||||
view = view, name = name, kwargs = kwargs
|
||||
)
|
||||
|
||||
def add_page(self, name, routes = [], view = views.PageView,
|
||||
sections = None, default = False, **kwargs):
|
||||
"""
|
||||
Add a view and declare it on the given routes.
|
||||
|
||||
* routes: list of routes or patterns, or tuple (route/pattern, view)
|
||||
to force a view to be used;
|
||||
* view: view to use by default to render the page;
|
||||
* sections: sections to display on the view;
|
||||
* default: use this as a default view;
|
||||
* kwargs: extra kwargs to pass to the view;
|
||||
|
||||
If view is a section, generate a PageView with this section as
|
||||
child. Note: the kwargs are passed to the PageView constructor.
|
||||
"""
|
||||
if view and issubclass(type(view), sections_.Section):
|
||||
sections, view = view, views.PageView
|
||||
|
||||
if not kwargs.get('menus'):
|
||||
kwargs['menus'] = self.menus
|
||||
if sections:
|
||||
self.register_exposures(sections)
|
||||
|
||||
view = view.as_view(website = self, sections = sections, **kwargs)
|
||||
|
||||
if not hasattr(routes, '__iter__'):
|
||||
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)
|
||||
self.__route_to_url(name, route, view, sections, kwargs)
|
||||
for route in routes
|
||||
]
|
||||
|
||||
def register_dl(self, name, model, sections = None, routes = None,
|
||||
def add_model(self, name, model, sections = None, routes = None,
|
||||
default = False,
|
||||
list_view = views.PostListView,
|
||||
detail_view = views.PostDetailView,
|
||||
list_kwargs = {}, detail_kwargs = {},
|
||||
as_default = False):
|
||||
**kwargs):
|
||||
"""
|
||||
Register a detail and list view for a given model, using
|
||||
routes.
|
||||
Add a model to the Website, register it and declare its routes.
|
||||
|
||||
Just a wrapper around `register`.
|
||||
* model: model to register
|
||||
* sections: sections to display in the *detail* view;
|
||||
* routes: routes to use for the *list* view -- cf. add_page.routes;
|
||||
* default: use as default route;
|
||||
* list_view: use it as view for lists;
|
||||
* detail_view: use it as view for details;
|
||||
* kwargs: extra kwargs arguments to pass to the view;
|
||||
"""
|
||||
# register the model and the routes
|
||||
reg = self.register_model(name, model, default)
|
||||
reg.routes.extend([
|
||||
route[0] if type(route) in (list,tuple) else route
|
||||
for route in routes
|
||||
])
|
||||
reg.routes.append(routes_.DetailRoute)
|
||||
|
||||
kwargs['model'] = model
|
||||
if sections:
|
||||
self.register(name, [ routes_.DetailRoute ], view = detail_view,
|
||||
model = model, sections = sections,
|
||||
as_default = as_default,
|
||||
**detail_kwargs)
|
||||
self.add_page(name, view = detail_view, sections = sections,
|
||||
routes = routes_.DetailRoute, default = default,
|
||||
**kwargs)
|
||||
if routes:
|
||||
self.register(name, routes, view = list_view,
|
||||
model = model, as_default = as_default,
|
||||
**list_kwargs)
|
||||
self.add_page(name, view = list_view, routes = routes,
|
||||
default = default, **kwargs)
|
||||
|
||||
def register_comments(self):
|
||||
"""
|
||||
|
@ -173,16 +189,12 @@ class Website:
|
|||
|
||||
Just a wrapper around `register`.
|
||||
"""
|
||||
self.register(
|
||||
self.add_model(
|
||||
'comment',
|
||||
view = views.PostListView,
|
||||
routes = [routes.ThreadRoute],
|
||||
model = models.Comment,
|
||||
routes = [routes.ThreadRoute],
|
||||
css_class = 'comments',
|
||||
list = sections.Comments(
|
||||
truncate = 30,
|
||||
fields = ['content','author','date','time'],
|
||||
)
|
||||
list = sections.Comments
|
||||
)
|
||||
|
||||
def set_menu(self, menu):
|
||||
|
@ -204,7 +216,7 @@ class Website:
|
|||
given route.
|
||||
"""
|
||||
for r in self.registry.values():
|
||||
if r.as_default and route in r.routes:
|
||||
if r.default and route in r.routes:
|
||||
return r
|
||||
|
||||
def reverse(self, model, route, use_default = True, **kwargs):
|
||||
|
@ -226,7 +238,7 @@ class Website:
|
|||
return ''
|
||||
|
||||
for r in self.registry.values():
|
||||
if r.as_default and route in r.routes:
|
||||
if r.default and route in r.routes:
|
||||
try:
|
||||
name = route.make_view_name(r.name)
|
||||
return reverse(name, kwargs = kwargs)
|
||||
|
|
|
@ -755,7 +755,7 @@ class Track(Related):
|
|||
blank=True,
|
||||
)
|
||||
pos_in_secs = models.BooleanField(
|
||||
_('use seconds'),
|
||||
_('seconds'),
|
||||
default = False,
|
||||
help_text=_('position in the playlist is expressed in seconds')
|
||||
)
|
||||
|
|
|
@ -95,7 +95,6 @@ class Player(sections.Section):
|
|||
|
||||
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,
|
||||
|
@ -220,7 +219,7 @@ class Diffusions(sections.List):
|
|||
|
||||
return ' / \n'.join([str_sched(sched)
|
||||
for sched in programs.Schedule.objects \
|
||||
.filter(program = self.object.related.pk)
|
||||
.filter(program = self.object and self.object.related.pk)
|
||||
])
|
||||
|
||||
|
||||
|
@ -256,27 +255,42 @@ class Sounds(sections.List):
|
|||
]
|
||||
|
||||
|
||||
class Schedule(Diffusions):
|
||||
|
||||
class ListByDate(sections.List):
|
||||
"""
|
||||
Render a list of diffusions in the form of a schedule
|
||||
List that add a navigation by date in its header.
|
||||
"""
|
||||
template_name = 'aircox/website/schedule.html'
|
||||
date = None
|
||||
nav_date_format = '%a. %d'
|
||||
fields = [ 'time', 'image', 'title']
|
||||
template_name = 'aircox/website/list_by_date.html'
|
||||
message_empty = ''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.add_css_class('schedule')
|
||||
model = None
|
||||
|
||||
@staticmethod
|
||||
def get_week_dates(date):
|
||||
date = None
|
||||
"""
|
||||
date of the items to print
|
||||
"""
|
||||
nav_days = 7
|
||||
"""
|
||||
number of days to display in the header
|
||||
"""
|
||||
nav_date_format = '%a. %d'
|
||||
"""
|
||||
format of dates to display in the header
|
||||
"""
|
||||
nav_per_week = True
|
||||
"""
|
||||
if true, print days in header by week
|
||||
"""
|
||||
|
||||
def nav_dates(self, date):
|
||||
"""
|
||||
Return a list of dates of the week of the given date.
|
||||
"""
|
||||
first = date - tz.timedelta(days=date.weekday())
|
||||
return [ first + tz.timedelta(days=i) for i in range(0, 7) ]
|
||||
first = int((self.nav_days - 1) / 2)
|
||||
first = date - tz.timedelta(days=date.weekday()) \
|
||||
if self.nav_per_week else \
|
||||
date - tz.timedelta(days=first)
|
||||
return [ first + tz.timedelta(days=i) for i in range(0, self.nav_days) ]
|
||||
|
||||
def date_or_default(self):
|
||||
if self.date:
|
||||
|
@ -287,40 +301,20 @@ class Schedule(Diffusions):
|
|||
day = int(self.kwargs['day']),
|
||||
hour = 0, minute = 0, second = 0,
|
||||
microsecond = 0)
|
||||
return tz.datetime.now()
|
||||
|
||||
def get_object_list(self):
|
||||
date = self.date_or_default()
|
||||
return routes.DateRoute.get_queryset(
|
||||
models.Diffusion, self.request, date.year, date.month,
|
||||
date.day
|
||||
).order_by('date')
|
||||
return tz.now()
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
|
||||
date = self.date_or_default()
|
||||
dates = [
|
||||
(date, models.Diffusion.reverse(
|
||||
routes.DateRoute,
|
||||
year = date.year, month = date.month, day = date.day
|
||||
))
|
||||
for date in self.get_week_dates(date)
|
||||
]
|
||||
dates = [ (date, self.get_date_url(date))
|
||||
for date in self.nav_dates(date) ]
|
||||
|
||||
next_week = dates[-1][0] + tz.timedelta(days=1)
|
||||
next_week = models.Diffusion.reverse(
|
||||
routes.DateRoute,
|
||||
year = next_week.year, month = next_week.month,
|
||||
day = next_week.day
|
||||
)
|
||||
next_week = self.get_date_url(next_week)
|
||||
|
||||
prev_week = dates[0][0] - tz.timedelta(days=1)
|
||||
prev_week = models.Diffusion.reverse(
|
||||
routes.DateRoute,
|
||||
year = prev_week.year, month = prev_week.month,
|
||||
day = prev_week.day
|
||||
)
|
||||
prev_week = self.get_date_url(prev_week)
|
||||
|
||||
context.update({
|
||||
'date': date,
|
||||
|
@ -330,15 +324,90 @@ class Schedule(Diffusions):
|
|||
})
|
||||
return context
|
||||
|
||||
@staticmethod
|
||||
def get_date_url(date):
|
||||
"""
|
||||
return a url to the list for the given date
|
||||
"""
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return None
|
||||
|
||||
|
||||
class Logs(Schedule):
|
||||
class Schedule(Diffusions,ListByDate):
|
||||
"""
|
||||
Render a list of diffusions in the form of a schedule
|
||||
"""
|
||||
fields = [ 'time', 'image', 'title', 'content', 'info', 'actions' ]
|
||||
truncate = 30
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.add_css_class('schedule')
|
||||
|
||||
def get_object_list(self):
|
||||
date = self.date_or_default()
|
||||
return routes.DateRoute.get_queryset(
|
||||
models.Diffusion, self.request, date.year, date.month,
|
||||
date.day
|
||||
).order_by('date')
|
||||
|
||||
@staticmethod
|
||||
def get_date_url(date):
|
||||
"""
|
||||
return an url for the given date
|
||||
"""
|
||||
return models.Diffusion.reverse(
|
||||
routes.DateRoute,
|
||||
year = date.year, month = date.month, day = date.day,
|
||||
)
|
||||
|
||||
|
||||
class Logs(ListByDate):
|
||||
"""
|
||||
Return a list of played stream sounds and diffusions.
|
||||
"""
|
||||
template_name = 'aircox/website/schedule.html'
|
||||
# HERE -- + rename aircox/website/schedule to dated_list
|
||||
|
||||
@staticmethod
|
||||
def make_item(log):
|
||||
"""
|
||||
Return a list of items to add to the playlist.
|
||||
"""
|
||||
if issubclass(type(log.related), programs.Diffusion):
|
||||
diff = log.related
|
||||
post = models.Diffusion.objects.filter(related = diff).first() \
|
||||
or models.Program.objects.filter(related = diff.program).first() \
|
||||
or ListItem(title = diff.program.name)
|
||||
post.date = diff.start
|
||||
return post
|
||||
|
||||
if issubclass(type(log.related), programs.Track):
|
||||
track = log.related
|
||||
post = ListItem(
|
||||
title = '{artist} — {name}'.format(
|
||||
artist = track.artist,
|
||||
name = track.name,
|
||||
),
|
||||
date = log.date,
|
||||
content = track.info,
|
||||
info = '♫',
|
||||
)
|
||||
return post
|
||||
|
||||
def get_object_list(self):
|
||||
station = self.view._website.station
|
||||
qs = station.get_played(
|
||||
models = [ programs.Diffusion, programs.Track ],
|
||||
).filter(
|
||||
date__year = int(year), date__month = int(month),
|
||||
date__day = int(day)
|
||||
)
|
||||
# TODO for each, exclude if there is a diffusion (that has not been logged)
|
||||
|
||||
return [ cl.make_item(log) for log in qs ]
|
||||
|
||||
@staticmethod
|
||||
def get_date_url(date):
|
||||
pass
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
{% extends 'aircox/cms/list.html' %}
|
||||
|
||||
{% block header %}
|
||||
<header>
|
||||
<script>
|
||||
sched_fields = [ {% for field in list.fields %}"fields={{ field }}",{% endfor %} ];
|
||||
sched_fields = sched_fields.join('&');
|
||||
</script>
|
||||
<a href="{{ prev_week }}" onclick="return Section.load_event(event, sched_fields);"><</a>
|
||||
{% for curr, url in dates %}
|
||||
<a href="{{ url }}" {% if curr == date %}class="selected" {% endif %}
|
||||
onclick="return Section.load_event(event);">
|
||||
{{ curr|date:'D. d' }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
<a href="{{ next_week }}" onclick="return Section.load_event(event, sched_fields);">></a>
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
Loading…
Reference in New Issue
Block a user