forked from rc/aircox
		
	work on comments, clean up a bit
This commit is contained in:
		
							
								
								
									
										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.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 taggit.managers import TaggableManager
 | 
			
		||||
@ -43,6 +44,43 @@ class ProxyPost:
 | 
			
		||||
            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):
 | 
			
		||||
    """
 | 
			
		||||
    Base model that can be used as is if wanted. Represent a generic
 | 
			
		||||
@ -84,7 +122,7 @@ class Post (models.Model):
 | 
			
		||||
    )
 | 
			
		||||
    content = models.TextField (
 | 
			
		||||
        _('description'),
 | 
			
		||||
        blank = True, null = True
 | 
			
		||||
        default = '',
 | 
			
		||||
    )
 | 
			
		||||
    image = models.ImageField(
 | 
			
		||||
        blank = True, null = True
 | 
			
		||||
@ -96,7 +134,7 @@ class Post (models.Model):
 | 
			
		||||
 | 
			
		||||
    search_fields = [ 'title', 'content' ]
 | 
			
		||||
 | 
			
		||||
    def get_proxy(self):
 | 
			
		||||
    def as_proxy(self):
 | 
			
		||||
        """
 | 
			
		||||
        Return a ProxyPost instance using this post
 | 
			
		||||
        """
 | 
			
		||||
@ -111,14 +149,36 @@ class Post (models.Model):
 | 
			
		||||
        if not queryset:
 | 
			
		||||
            queryset = cl.objects
 | 
			
		||||
        thread_type = ContentType.objects.get_for_model(thread)
 | 
			
		||||
        qs = queryset.filter(thread_id = thread.pk,
 | 
			
		||||
                              thread_type__pk = thread_type.id)
 | 
			
		||||
        qs = queryset.filter(
 | 
			
		||||
            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
 | 
			
		||||
 | 
			
		||||
    def detail_url(self):
 | 
			
		||||
        return self.route_url(routes.DetailRoute,
 | 
			
		||||
                              { '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
 | 
			
		||||
    def route_url(cl, route, kwargs = None):
 | 
			
		||||
        name = cl._website.name_of_model(cl)
 | 
			
		||||
@ -198,6 +258,24 @@ class RelatedPostBase (models.base.ModelBase):
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        # TODO: allow proxy models and better inheritance
 | 
			
		||||
        # TODO: check bindings
 | 
			
		||||
@ -213,9 +291,11 @@ class RelatedPostBase (models.base.ModelBase):
 | 
			
		||||
        }.items() if not attrs.get(x) })
 | 
			
		||||
 | 
			
		||||
        model = super().__new__(cl, name, bases, attrs)
 | 
			
		||||
        print(model, model.related)
 | 
			
		||||
        cl.register(rel.model, model)
 | 
			
		||||
 | 
			
		||||
        # auto create and/or update
 | 
			
		||||
        cl.make_auto_create(model)
 | 
			
		||||
 | 
			
		||||
        # name clashes
 | 
			
		||||
        name = rel.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.
 | 
			
		||||
        * field_args: dict of arguments to pass to the ForeignKey constructor,
 | 
			
		||||
            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!
 | 
			
		||||
        * There is no check of permissions when related object is synchronised
 | 
			
		||||
@ -288,6 +371,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
        rel_to_post = False
 | 
			
		||||
        thread_model = None
 | 
			
		||||
        field_args = None
 | 
			
		||||
        auto_create = False
 | 
			
		||||
 | 
			
		||||
    def get_rel_attr(self, 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
 | 
			
		||||
        """
 | 
			
		||||
        rel = self._relation
 | 
			
		||||
        if not rel.bindings:
 | 
			
		||||
        if not self.related or not rel.bindings:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
        """
 | 
			
		||||
        rel = self._relation
 | 
			
		||||
        if not rel.bindings:
 | 
			
		||||
        if not self.related or not rel.bindings:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
        # applications, e.g. using signals.
 | 
			
		||||
        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):
 | 
			
		||||
        # TODO handle when related change
 | 
			
		||||
        if not self.title and self.related:
 | 
			
		||||
            self.title = self.get_rel_attr('title')
 | 
			
		||||
        if self._relation.post_to_rel:
 | 
			
		||||
            self.post_to_rel(save = True)
 | 
			
		||||
    def save (self, avoid_sync = False, *args, **kwargs):
 | 
			
		||||
        """
 | 
			
		||||
        If avoid_relation, do not synchronise the post/related object.
 | 
			
		||||
        """
 | 
			
		||||
        if not avoid_sync:
 | 
			
		||||
            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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
@ -25,6 +26,7 @@ body {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** detail and list content **/
 | 
			
		||||
main .section {
 | 
			
		||||
/*    width: calc(50% - 2em);
 | 
			
		||||
    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 %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{{ content }}
 | 
			
		||||
{{ content|safe }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,21 +10,21 @@
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{% if header %}
 | 
			
		||||
<header class="section_header">
 | 
			
		||||
<header>
 | 
			
		||||
    {% block section_header %}
 | 
			
		||||
    {{ header }}
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
</header>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
<div class="section_content">
 | 
			
		||||
<div class="content">
 | 
			
		||||
    {% block section_content %}
 | 
			
		||||
    {{ content|safe }}
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% if footer %}
 | 
			
		||||
<footer class="section_footer">
 | 
			
		||||
<footer>
 | 
			
		||||
    {% block section_footer %}
 | 
			
		||||
    {{ footer }}
 | 
			
		||||
    {% 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 %}
 | 
			
		||||
 | 
			
		||||
% block section_content %}
 | 
			
		||||
{% block section_content %}
 | 
			
		||||
<ul style="padding:0; margin:0">
 | 
			
		||||
    {% for item in object_list %}
 | 
			
		||||
    <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.base import View
 | 
			
		||||
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:
 | 
			
		||||
    website = None  # corresponding website
 | 
			
		||||
@ -24,7 +26,7 @@ class PostBaseView:
 | 
			
		||||
 | 
			
		||||
        if not self.embed:
 | 
			
		||||
            context['menus'] = {
 | 
			
		||||
                k: v.get(self.request, website = self.website, **kwargs)
 | 
			
		||||
                k: v.get(self.request, object = self.object, **kwargs)
 | 
			
		||||
                for k, v in {
 | 
			
		||||
                    k: self.website.get_menu(k)
 | 
			
		||||
                    for k in self.website.menu_layouts
 | 
			
		||||
@ -48,7 +50,7 @@ class PostListView(PostBaseView, ListView):
 | 
			
		||||
    """
 | 
			
		||||
    template_name = 'aircox/cms/list.html'
 | 
			
		||||
    allow_empty = True
 | 
			
		||||
    paginate_by = 50
 | 
			
		||||
    paginate_by = 25
 | 
			
		||||
    model = None
 | 
			
		||||
 | 
			
		||||
    route = None
 | 
			
		||||
@ -111,6 +113,9 @@ class PostListView(PostBaseView, ListView):
 | 
			
		||||
        return ''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from honeypot.decorators import verify_honeypot_value
 | 
			
		||||
from aircox.cms.forms import CommentForm
 | 
			
		||||
 | 
			
		||||
class PostDetailView(DetailView, PostBaseView):
 | 
			
		||||
    """
 | 
			
		||||
    Detail view for posts and children
 | 
			
		||||
@ -124,7 +129,7 @@ class PostDetailView(DetailView, PostBaseView):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, sections = None, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.sections = Sections(sections = sections)
 | 
			
		||||
        self.sections = sections or []
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        if self.request.GET.get('embed'):
 | 
			
		||||
@ -143,44 +148,42 @@ class PostDetailView(DetailView, PostBaseView):
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
    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'
 | 
			
		||||
    tag = 'div'
 | 
			
		||||
    tag = 'nav'
 | 
			
		||||
    classes = ''
 | 
			
		||||
    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 = ''
 | 
			
		||||
    tag = 'nav'
 | 
			
		||||
    enabled = True
 | 
			
		||||
    position = ''   # top, left, bottom, right, header, footer, page_top, page_bottom
 | 
			
		||||
    sections = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
@ -191,4 +194,23 @@ class Menu(Sections):
 | 
			
		||||
            self.attrs['name'] = 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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user