work on comments, clean up a bit
This commit is contained in:
parent
f8f3beb124
commit
a989e53da4
|
@ -23,7 +23,8 @@ Later we would provide a package, but now we have other priorities.
|
||||||
### settings.py
|
### settings.py
|
||||||
* There must be `BASE_DIR` or `PROJECT_ROOT` defined in order to make liquidsoap working (that must call manage.py using an absolute path).
|
* There must be `BASE_DIR` or `PROJECT_ROOT` defined in order to make liquidsoap working (that must call manage.py using an absolute path).
|
||||||
* INSTALLED_APPS:
|
* INSTALLED_APPS:
|
||||||
- dependencies: `'taggit'`, `'easy_thumbnails'`
|
- dependencies: `'taggit'` (*programs* and *cms* applications),
|
||||||
|
`'easy_thumbnails'` (*cms*), `'honeypot'` (*cms*)
|
||||||
- optional dependencies (in order to make users' life easier): `'autocomplete_light'`, `'suit'`
|
- optional dependencies (in order to make users' life easier): `'autocomplete_light'`, `'suit'`
|
||||||
- aircox: `'aircox.programs'`, `'aircox.liquidsoap'`, `'aircox.cms'`
|
- aircox: `'aircox.programs'`, `'aircox.liquidsoap'`, `'aircox.cms'`
|
||||||
|
|
||||||
|
|
148
cms/models.py
148
cms/models.py
|
@ -7,7 +7,8 @@ from django.utils.text import slugify
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
from django.db.models.signals import post_init, post_save, post_delete
|
|
||||||
|
from django.db.models.signals import Signal, post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from taggit.managers import TaggableManager
|
from taggit.managers import TaggableManager
|
||||||
|
@ -43,6 +44,43 @@ class ProxyPost:
|
||||||
self.detail_url = thread.detail_url()
|
self.detail_url = thread.detail_url()
|
||||||
|
|
||||||
|
|
||||||
|
class Comment(models.Model):
|
||||||
|
thread_type = models.ForeignKey(
|
||||||
|
ContentType,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
blank = True, null = True
|
||||||
|
)
|
||||||
|
thread_id = models.PositiveIntegerField(
|
||||||
|
blank = True, null = True
|
||||||
|
)
|
||||||
|
thread = GenericForeignKey('thread_type', 'thread_id')
|
||||||
|
|
||||||
|
published = models.BooleanField(
|
||||||
|
verbose_name = _('public'),
|
||||||
|
default = False
|
||||||
|
)
|
||||||
|
|
||||||
|
author = models.CharField(
|
||||||
|
verbose_name = _('author'),
|
||||||
|
max_length = 32,
|
||||||
|
)
|
||||||
|
email = models.EmailField(
|
||||||
|
verbose_name = _('email'),
|
||||||
|
blank = True, null = True,
|
||||||
|
)
|
||||||
|
url = models.URLField(
|
||||||
|
verbose_name = _('website'),
|
||||||
|
blank = True, null = True,
|
||||||
|
)
|
||||||
|
date = models.DateTimeField(
|
||||||
|
_('date'),
|
||||||
|
default = timezone.datetime.now
|
||||||
|
)
|
||||||
|
content = models.TextField (
|
||||||
|
_('comment'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Post (models.Model):
|
class Post (models.Model):
|
||||||
"""
|
"""
|
||||||
Base model that can be used as is if wanted. Represent a generic
|
Base model that can be used as is if wanted. Represent a generic
|
||||||
|
@ -84,7 +122,7 @@ class Post (models.Model):
|
||||||
)
|
)
|
||||||
content = models.TextField (
|
content = models.TextField (
|
||||||
_('description'),
|
_('description'),
|
||||||
blank = True, null = True
|
default = '',
|
||||||
)
|
)
|
||||||
image = models.ImageField(
|
image = models.ImageField(
|
||||||
blank = True, null = True
|
blank = True, null = True
|
||||||
|
@ -96,7 +134,7 @@ class Post (models.Model):
|
||||||
|
|
||||||
search_fields = [ 'title', 'content' ]
|
search_fields = [ 'title', 'content' ]
|
||||||
|
|
||||||
def get_proxy(self):
|
def as_proxy(self):
|
||||||
"""
|
"""
|
||||||
Return a ProxyPost instance using this post
|
Return a ProxyPost instance using this post
|
||||||
"""
|
"""
|
||||||
|
@ -111,14 +149,36 @@ class Post (models.Model):
|
||||||
if not queryset:
|
if not queryset:
|
||||||
queryset = cl.objects
|
queryset = cl.objects
|
||||||
thread_type = ContentType.objects.get_for_model(thread)
|
thread_type = ContentType.objects.get_for_model(thread)
|
||||||
qs = queryset.filter(thread_id = thread.pk,
|
qs = queryset.filter(
|
||||||
thread_type__pk = thread_type.id)
|
thread_id = thread.pk,
|
||||||
|
thread_type__pk = thread_type.id
|
||||||
|
)
|
||||||
|
return qs
|
||||||
|
|
||||||
|
def get_comments(self):
|
||||||
|
"""
|
||||||
|
Return comments pointing to this post
|
||||||
|
"""
|
||||||
|
type = ContentType.objects.get_for_model(self)
|
||||||
|
qs = Comment.objects.filter(
|
||||||
|
thread_id = self.pk,
|
||||||
|
thread_type__pk = type.pk
|
||||||
|
)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def detail_url(self):
|
def detail_url(self):
|
||||||
return self.route_url(routes.DetailRoute,
|
return self.route_url(routes.DetailRoute,
|
||||||
{ 'pk': self.pk, 'slug': slugify(self.title) })
|
{ 'pk': self.pk, 'slug': slugify(self.title) })
|
||||||
|
|
||||||
|
|
||||||
|
def get_object_list(self, request, object, **kwargs):
|
||||||
|
type = ContentType.objects.get_for_model(object)
|
||||||
|
qs = Comment.objects.filter(
|
||||||
|
thread_id = object.pk,
|
||||||
|
thread_type__pk = type.pk
|
||||||
|
)
|
||||||
|
return qs
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def route_url(cl, route, kwargs = None):
|
def route_url(cl, route, kwargs = None):
|
||||||
name = cl._website.name_of_model(cl)
|
name = cl._website.name_of_model(cl)
|
||||||
|
@ -198,6 +258,24 @@ class RelatedPostBase (models.base.ModelBase):
|
||||||
|
|
||||||
return rel
|
return rel
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_auto_create(cl, model):
|
||||||
|
if not model._relation.rel_to_post:
|
||||||
|
return
|
||||||
|
|
||||||
|
def handler(sender, instance, created, *args, **kwargs):
|
||||||
|
rel = model._relation
|
||||||
|
post = model.objects.filter(related = instance)
|
||||||
|
if post.count():
|
||||||
|
post = post[0]
|
||||||
|
elif rel.auto_create:
|
||||||
|
post = model(related = instance)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
post.rel_to_post()
|
||||||
|
post.save(avoid_sync = True)
|
||||||
|
post_save.connect(handler, model._relation.model, False)
|
||||||
|
|
||||||
def __new__ (cl, name, bases, attrs):
|
def __new__ (cl, name, bases, attrs):
|
||||||
# TODO: allow proxy models and better inheritance
|
# TODO: allow proxy models and better inheritance
|
||||||
# TODO: check bindings
|
# TODO: check bindings
|
||||||
|
@ -213,9 +291,11 @@ class RelatedPostBase (models.base.ModelBase):
|
||||||
}.items() if not attrs.get(x) })
|
}.items() if not attrs.get(x) })
|
||||||
|
|
||||||
model = super().__new__(cl, name, bases, attrs)
|
model = super().__new__(cl, name, bases, attrs)
|
||||||
print(model, model.related)
|
|
||||||
cl.register(rel.model, model)
|
cl.register(rel.model, model)
|
||||||
|
|
||||||
|
# auto create and/or update
|
||||||
|
cl.make_auto_create(model)
|
||||||
|
|
||||||
# name clashes
|
# name clashes
|
||||||
name = rel.model._meta.object_name
|
name = rel.model._meta.object_name
|
||||||
if name == model._meta.object_name:
|
if name == model._meta.object_name:
|
||||||
|
@ -275,6 +355,9 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
model generated for the bindings.thread object.
|
model generated for the bindings.thread object.
|
||||||
* field_args: dict of arguments to pass to the ForeignKey constructor,
|
* field_args: dict of arguments to pass to the ForeignKey constructor,
|
||||||
such as: ForeignKey(related_model, **field_args)
|
such as: ForeignKey(related_model, **field_args)
|
||||||
|
* auto_create: automatically create a RelatedPost for each new item of
|
||||||
|
the related object and init it with bounded values. Use signals
|
||||||
|
'', ''.
|
||||||
|
|
||||||
Be careful with post_to_rel!
|
Be careful with post_to_rel!
|
||||||
* There is no check of permissions when related object is synchronised
|
* There is no check of permissions when related object is synchronised
|
||||||
|
@ -288,6 +371,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
rel_to_post = False
|
rel_to_post = False
|
||||||
thread_model = None
|
thread_model = None
|
||||||
field_args = None
|
field_args = None
|
||||||
|
auto_create = False
|
||||||
|
|
||||||
def get_rel_attr(self, attr):
|
def get_rel_attr(self, attr):
|
||||||
attr = self._relation.bindings.get(attr)
|
attr = self._relation.bindings.get(attr)
|
||||||
|
@ -306,7 +390,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
Note: does not check if Relation.post_to_rel is True
|
Note: does not check if Relation.post_to_rel is True
|
||||||
"""
|
"""
|
||||||
rel = self._relation
|
rel = self._relation
|
||||||
if not rel.bindings:
|
if not self.related or not rel.bindings:
|
||||||
return
|
return
|
||||||
|
|
||||||
for attr, rel_attr in rel.bindings.items():
|
for attr, rel_attr in rel.bindings.items():
|
||||||
|
@ -331,7 +415,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
Note: does not check if Relation.post_to_rel is True
|
Note: does not check if Relation.post_to_rel is True
|
||||||
"""
|
"""
|
||||||
rel = self._relation
|
rel = self._relation
|
||||||
if not rel.bindings:
|
if not self.related or not rel.bindings:
|
||||||
return
|
return
|
||||||
|
|
||||||
has_changed = False
|
has_changed = False
|
||||||
|
@ -362,44 +446,16 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
|
||||||
# we use this method for sync, in order to avoid intrusive code on other
|
# we use this method for sync, in order to avoid intrusive code on other
|
||||||
# applications, e.g. using signals.
|
# applications, e.g. using signals.
|
||||||
if self.pk and self._relation.rel_to_post:
|
if self.pk and self._relation.rel_to_post:
|
||||||
self.rel_to_post(save = False)
|
self.rel_to_post(False)
|
||||||
|
|
||||||
def save (self, *args, **kwargs):
|
def save (self, avoid_sync = False, *args, **kwargs):
|
||||||
# TODO handle when related change
|
"""
|
||||||
if not self.title and self.related:
|
If avoid_relation, do not synchronise the post/related object.
|
||||||
self.title = self.get_rel_attr('title')
|
"""
|
||||||
if self._relation.post_to_rel:
|
if not avoid_sync:
|
||||||
self.post_to_rel(save = True)
|
if not self.pk and self._relation.rel_to_post:
|
||||||
|
self.rel_to_post(False)
|
||||||
|
if self._relation.post_to_rel:
|
||||||
|
self.post_to_rel(True)
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Comment(models.Model):
|
|
||||||
thread_type = models.ForeignKey(
|
|
||||||
ContentType,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
blank = True, null = True
|
|
||||||
)
|
|
||||||
thread_id = models.PositiveIntegerField(
|
|
||||||
blank = True, null = True
|
|
||||||
)
|
|
||||||
thread = GenericForeignKey('thread_type', 'thread_id')
|
|
||||||
|
|
||||||
author = models.TextField(
|
|
||||||
verbose_name = _('author'),
|
|
||||||
blank = True, null = True,
|
|
||||||
)
|
|
||||||
email = models.EmailField(
|
|
||||||
verbose_name = _('email'),
|
|
||||||
blank = True, null = True,
|
|
||||||
)
|
|
||||||
date = models.DateTimeField(
|
|
||||||
_('date'),
|
|
||||||
default = timezone.datetime.now
|
|
||||||
)
|
|
||||||
content = models.TextField (
|
|
||||||
_('description'),
|
|
||||||
blank = True, null = True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/** main layout **/
|
||||||
body {
|
body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -25,6 +26,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** detail and list content **/
|
||||||
main .section {
|
main .section {
|
||||||
/* width: calc(50% - 2em);
|
/* width: calc(50% - 2em);
|
||||||
display: inline-block; */
|
display: inline-block; */
|
||||||
|
@ -49,3 +51,36 @@ main .section {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** comments **/
|
||||||
|
.comment-form label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-form input:not([type=checkbox]),
|
||||||
|
.comment-form textarea {
|
||||||
|
display: inline-block;
|
||||||
|
width: calc(100% - 5em);
|
||||||
|
max-height: 6em;
|
||||||
|
margin: 0.2em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-form input[type=checkbox],
|
||||||
|
.comment-form button[type=submit] {
|
||||||
|
max-width: 4em;
|
||||||
|
vertical-align:bottom;
|
||||||
|
margin: 0.2em 0em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-form .extra {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-form input[type="checkbox"]:checked + .extra {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,6 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{{ content }}
|
{{ content|safe }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,21 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if header %}
|
{% if header %}
|
||||||
<header class="section_header">
|
<header>
|
||||||
{% block section_header %}
|
{% block section_header %}
|
||||||
{{ header }}
|
{{ header }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</header>
|
</header>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="section_content">
|
<div class="content">
|
||||||
{% block section_content %}
|
{% block section_content %}
|
||||||
{{ content|safe }}
|
{{ content|safe }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if footer %}
|
{% if footer %}
|
||||||
<footer class="section_footer">
|
<footer>
|
||||||
{% block section_footer %}
|
{% block section_footer %}
|
||||||
{{ footer }}
|
{{ footer }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
49
cms/templates/aircox/cms/section_comments.html
Normal file
49
cms/templates/aircox/cms/section_comments.html
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{% extends "aircox/cms/section.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load honeypot %}
|
||||||
|
|
||||||
|
{% block section_content %}
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
<form action="" method="POST" class="comment-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% render_honeypot_field "hp_website" %}
|
||||||
|
<div>
|
||||||
|
{{ form.author.errors }}
|
||||||
|
{{ form.author }}
|
||||||
|
<input type="checkbox" value="1">
|
||||||
|
<div class="extra">
|
||||||
|
{{ form.email.errors }}
|
||||||
|
{{ form.email }}
|
||||||
|
{{ form.url.errors }}
|
||||||
|
{{ form.url }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ form.content.errors }}
|
||||||
|
{{ form.content }}
|
||||||
|
<button type="submit">{% trans "Post!" %}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<ul style="padding:0; margin:0">
|
||||||
|
{% for item in object_list %}
|
||||||
|
<li id="comment-{{ item.id }}" class="{{item.css}}">
|
||||||
|
{{ item.content }}
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<a href="{% if item.url %}{{ item.url }}{% else %}#{% endif %}">{{ item.author }}</a>
|
||||||
|
|
||||||
|
<time datetime="{{ item.date }}">
|
||||||
|
{{ item.date|date:'l d F Y' }},
|
||||||
|
{{ item.date|time:'H\hi' }}
|
||||||
|
</time>
|
||||||
|
|
||||||
|
<a href="#comment-{{ item.id }}">#{{ item.id }}</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{% load thumbnail %}
|
{% load thumbnail %}
|
||||||
|
|
||||||
% block section_content %}
|
{% block section_content %}
|
||||||
<ul style="padding:0; margin:0">
|
<ul style="padding:0; margin:0">
|
||||||
{% for item in object_list %}
|
{% for item in object_list %}
|
||||||
<li class="{{item.css}}">
|
<li class="{{item.css}}">
|
||||||
|
|
86
cms/views.py
86
cms/views.py
|
@ -3,7 +3,9 @@ from django.template.loader import render_to_string
|
||||||
from django.views.generic import ListView, DetailView
|
from django.views.generic import ListView, DetailView
|
||||||
from django.views.generic.base import View
|
from django.views.generic.base import View
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||||
|
from django.http import Http404
|
||||||
|
|
||||||
|
from django.views.decorators.http import require_http_methods
|
||||||
|
|
||||||
class PostBaseView:
|
class PostBaseView:
|
||||||
website = None # corresponding website
|
website = None # corresponding website
|
||||||
|
@ -24,7 +26,7 @@ class PostBaseView:
|
||||||
|
|
||||||
if not self.embed:
|
if not self.embed:
|
||||||
context['menus'] = {
|
context['menus'] = {
|
||||||
k: v.get(self.request, website = self.website, **kwargs)
|
k: v.get(self.request, object = self.object, **kwargs)
|
||||||
for k, v in {
|
for k, v in {
|
||||||
k: self.website.get_menu(k)
|
k: self.website.get_menu(k)
|
||||||
for k in self.website.menu_layouts
|
for k in self.website.menu_layouts
|
||||||
|
@ -48,7 +50,7 @@ class PostListView(PostBaseView, ListView):
|
||||||
"""
|
"""
|
||||||
template_name = 'aircox/cms/list.html'
|
template_name = 'aircox/cms/list.html'
|
||||||
allow_empty = True
|
allow_empty = True
|
||||||
paginate_by = 50
|
paginate_by = 25
|
||||||
model = None
|
model = None
|
||||||
|
|
||||||
route = None
|
route = None
|
||||||
|
@ -111,6 +113,9 @@ class PostListView(PostBaseView, ListView):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
from honeypot.decorators import verify_honeypot_value
|
||||||
|
from aircox.cms.forms import CommentForm
|
||||||
|
|
||||||
class PostDetailView(DetailView, PostBaseView):
|
class PostDetailView(DetailView, PostBaseView):
|
||||||
"""
|
"""
|
||||||
Detail view for posts and children
|
Detail view for posts and children
|
||||||
|
@ -124,7 +129,7 @@ class PostDetailView(DetailView, PostBaseView):
|
||||||
|
|
||||||
def __init__(self, sections = None, *args, **kwargs):
|
def __init__(self, sections = None, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.sections = Sections(sections = sections)
|
self.sections = sections or []
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.request.GET.get('embed'):
|
if self.request.GET.get('embed'):
|
||||||
|
@ -143,44 +148,42 @@ 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())
|
context.update(self.get_base_context())
|
||||||
context['content'] = self.sections.get(request, object = self.object,
|
|
||||||
**kwargs)
|
kwargs['object'] = self.object
|
||||||
|
context['content'] = ''.join([
|
||||||
|
section.get(request = self.request, **kwargs)
|
||||||
|
for section in self.sections
|
||||||
|
])
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Handle new comments
|
||||||
|
"""
|
||||||
|
self.object = self.get_object()
|
||||||
|
if not self.object:
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
class Sections(View):
|
comment_form = CommentForm(request.POST)
|
||||||
|
if not comment_form.is_valid() or verify_honeypot_value(request, 'hp_website'):
|
||||||
|
raise Http404()
|
||||||
|
comment = comment_form.save(commit=False)
|
||||||
|
comment.thread = self.object
|
||||||
|
comment.save()
|
||||||
|
|
||||||
|
return self.get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Menu(View):
|
||||||
template_name = 'aircox/cms/content_object.html'
|
template_name = 'aircox/cms/content_object.html'
|
||||||
tag = 'div'
|
tag = 'nav'
|
||||||
classes = ''
|
classes = ''
|
||||||
attrs = ''
|
attrs = ''
|
||||||
sections = None
|
|
||||||
|
|
||||||
def __init__ (self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.classes += ' sections'
|
|
||||||
|
|
||||||
def get_context_data(self, request, object = None, **kwargs):
|
|
||||||
return {
|
|
||||||
'tag': self.tag,
|
|
||||||
'classes': self.classes,
|
|
||||||
'attrs': self.attrs,
|
|
||||||
'content': ''.join([
|
|
||||||
section.get(request, object = object, **kwargs)
|
|
||||||
for section in self.sections or []
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
def get(self, request, object = None, **kwargs):
|
|
||||||
self.request = request
|
|
||||||
context = self.get_context_data(request, object, **kwargs)
|
|
||||||
return render_to_string(self.template_name, context)
|
|
||||||
|
|
||||||
|
|
||||||
class Menu(Sections):
|
|
||||||
name = ''
|
name = ''
|
||||||
tag = 'nav'
|
|
||||||
enabled = True
|
enabled = True
|
||||||
position = '' # top, left, bottom, right, header, footer, page_top, page_bottom
|
position = '' # top, left, bottom, right, header, footer, page_top, page_bottom
|
||||||
|
sections = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
@ -191,4 +194,23 @@ class Menu(Sections):
|
||||||
self.attrs['name'] = self.name
|
self.attrs['name'] = self.name
|
||||||
self.attrs['id'] = self.name
|
self.attrs['id'] = self.name
|
||||||
|
|
||||||
|
def get_context_data(self, request, object = None, **kwargs):
|
||||||
|
kwargs['object'] = object
|
||||||
|
|
||||||
|
return {
|
||||||
|
'tag': self.tag,
|
||||||
|
'classes': self.classes,
|
||||||
|
'attrs': self.attrs,
|
||||||
|
'content': ''.join([
|
||||||
|
section.get(request, **kwargs)
|
||||||
|
for section in self.sections
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
def get(self, request, object = None, **kwargs):
|
||||||
|
self.request = request
|
||||||
|
context = self.get_context_data(request, object, **kwargs)
|
||||||
|
return render_to_string(self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ class Sound(Nameable):
|
||||||
|
|
||||||
type = models.SmallIntegerField(
|
type = models.SmallIntegerField(
|
||||||
verbose_name = _('type'),
|
verbose_name = _('type'),
|
||||||
choices = [ (y, _(x)) for x,y in Type.__members__.items() ],
|
choices = [ (int(y), _(x)) for x,y in Type.__members__.items() ],
|
||||||
blank = True, null = True
|
blank = True, null = True
|
||||||
)
|
)
|
||||||
path = models.FilePathField(
|
path = models.FilePathField(
|
||||||
|
@ -571,7 +571,7 @@ class Diffusion(models.Model):
|
||||||
# specific
|
# specific
|
||||||
type = models.SmallIntegerField(
|
type = models.SmallIntegerField(
|
||||||
verbose_name = _('type'),
|
verbose_name = _('type'),
|
||||||
choices = [ (y, _(x)) for x,y in Type.__members__.items() ],
|
choices = [ (int(y), _(x)) for x,y in Type.__members__.items() ],
|
||||||
)
|
)
|
||||||
initial = models.ForeignKey (
|
initial = models.ForeignKey (
|
||||||
'self',
|
'self',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user