From: Emilie Date: Thu, 18 Aug 2016 17:23:39 +0000 (+0200) Subject: Abstract DynamicContent + DynamicContentHomeSlider + DynamicContentHomeBody X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=5f42660ae4b8967ae02855cf118afc87a106b3f1;p=mezzo.git Abstract DynamicContent + DynamicContentHomeSlider + DynamicContentHomeBody --- diff --git a/app/local_settings.py b/app/local_settings.py index 63179b76..ce39e804 100644 --- a/app/local_settings.py +++ b/app/local_settings.py @@ -69,7 +69,7 @@ SITE_TAGLINE = 'Institut de Recherche et de Coordination Acoustique et Musique' SILENCED_SYSTEM_CHECKS = ['fields.W342',] ADMIN_MENU_ORDER = ( - (_('Pages'), ('pages.Page', 'organization-featured.Featured',)), + (_('Pages'), ('pages.Page', 'organization-featured.Featured', 'organization-pages.Home')), (_('Media'), ('organization-media.Video', 'organization-media.VideoCategory', 'organization-media.Audio', 'organization-media.Playlist', 'organization-media.Photo', (_('Media Library'), 'fb_browse'),)), (_('Events'), ('mezzanine_agenda.Event', 'mezzanine_agenda.EventLocation', 'mezzanine_agenda.EventCategory', 'mezzanine_agenda.EventPrice',)), (_('Magazine'), ('organization-magazine.Article', 'organization-magazine.Brief',)), diff --git a/app/organization/core/models.py b/app/organization/core/models.py index eca58a77..118ddd46 100644 --- a/app/organization/core/models.py +++ b/app/organization/core/models.py @@ -2,6 +2,8 @@ from django.db import models from django.conf import settings from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse, reverse_lazy +from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes.fields import GenericForeignKey from mezzanine.pages.models import Page, RichText from mezzanine.core.fields import RichTextField, OrderField, FileField @@ -81,6 +83,29 @@ class Block(RichText, Titled, Orderable): abstract = True +class DynamicContent(models.Model): + + # used for autocomplete but hidden in admin + content_type = models.ForeignKey( + ContentType, + verbose_name=_('content type'), + null=True, + blank=True, + editable=False, + ) + + # used for autocomplete but hidden in admin + object_id = models.PositiveIntegerField( + verbose_name=_('related object'), + null=True, + editable=False, + ) + + content_object = GenericForeignKey('content_type', 'object_id') + + class Meta: + abstract = True + class Image(Description, Orderable): file = FileField(_("Image"), max_length=1024, format="Image", upload_to="images") diff --git a/app/organization/magazine/forms.py b/app/organization/magazine/forms.py index b47fb511..0a9768ca 100644 --- a/app/organization/magazine/forms.py +++ b/app/organization/magazine/forms.py @@ -9,17 +9,11 @@ from mezzanine_agenda.models import Event class BriefForm(autocomplete.FutureModelForm): - # selected_object = forms.ModelChoiceField( - # queryset=ContentType.objects.all(), - # widget=autocomplete.ModelSelect2(url='object-autocomplete') - # ) - content_object = dal_queryset_sequence.fields.QuerySetSequenceModelField( queryset=autocomplete.QuerySetSequence( Article.objects.all(), Event.objects.all(), BasicPage.objects.all(), - # ContentType.objects.all(), ), required=False, widget=dal_select2_queryset_sequence.widgets.QuerySetSequenceSelect2('object-autocomplete'), diff --git a/app/organization/media/views.py b/app/organization/media/views.py index 933be23d..f55156b2 100644 --- a/app/organization/media/views.py +++ b/app/organization/media/views.py @@ -2,7 +2,10 @@ from django.shortcuts import render from organization.media.models import * from organization.core.views import * - +from dal import autocomplete +from dal_select2_queryset_sequence.views import Select2QuerySetSequenceView +from mezzanine_agenda.models import Event +from organization.magazine.models import Article, Topic, Brief class VideoListView(ListView): diff --git a/app/organization/pages/__init__.py b/app/organization/pages/__init__.py new file mode 100644 index 00000000..21dc396c --- /dev/null +++ b/app/organization/pages/__init__.py @@ -0,0 +1,10 @@ +""" +Provides abstract models and admin features used throughout the various +Mezzanine apps. +""" +from __future__ import unicode_literals + +from mezzanine import __version__ # noqa + + +default_app_config = 'organization.pages.apps.OrganizationPagesConfig' diff --git a/app/organization/pages/admin.py b/app/organization/pages/admin.py new file mode 100644 index 00000000..e0ae08e7 --- /dev/null +++ b/app/organization/pages/admin.py @@ -0,0 +1,28 @@ +from django.contrib import admin + +from django.contrib import admin +from copy import deepcopy +from mezzanine.core.admin import * +from mezzanine.pages.admin import PageAdmin +from organization.core.models import * +from organization.pages.models import DynamicContentHomeSlider, DynamicContentHomeBody, Home +from organization.pages.forms import DynamicContentHomeSliderForm, DynamicContentHomeBodyForm + +# Register your models here. + +class DynamicContentHomeSliderInline(StackedDynamicInlineAdmin): + + model = DynamicContentHomeSlider + form = DynamicContentHomeSliderForm + +class DynamicContentHomeBodyInline(StackedDynamicInlineAdmin): + + model = DynamicContentHomeBody + form = DynamicContentHomeBodyForm + +class HomeAdminDisplayable(BaseTranslationModelAdmin): + + inlines = [DynamicContentHomeSliderInline, DynamicContentHomeBodyInline ] + + +admin.site.register(Home, HomeAdminDisplayable) diff --git a/app/organization/pages/apps.py b/app/organization/pages/apps.py new file mode 100644 index 00000000..f79213e6 --- /dev/null +++ b/app/organization/pages/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + +class OrganizationPagesConfig(AppConfig): + name = 'organization.pages' + label = 'organization-pages' diff --git a/app/organization/pages/forms.py b/app/organization/pages/forms.py new file mode 100644 index 00000000..8b5e9735 --- /dev/null +++ b/app/organization/pages/forms.py @@ -0,0 +1,42 @@ +from dal import autocomplete + +import dal_queryset_sequence +import dal_select2_queryset_sequence + +from organization.magazine.models import Article, Topic, Brief +from organization.core.models import BasicPage +from mezzanine_agenda.models import Event +from organization.pages.models import DynamicContentHomeSlider, DynamicContentHomeBody + +class DynamicContentHomeSliderForm(autocomplete.FutureModelForm): + + content_object = dal_queryset_sequence.fields.QuerySetSequenceModelField( + queryset=autocomplete.QuerySetSequence( + Article.objects.all(), + Event.objects.all(), + BasicPage.objects.all(), + ), + required=False, + widget=dal_select2_queryset_sequence.widgets.QuerySetSequenceSelect2('dynamic-content-home-slider'), + ) + + class Meta: + model = DynamicContentHomeSlider + fields = ('__all__') + +class DynamicContentHomeBodyForm(autocomplete.FutureModelForm): + + content_object = dal_queryset_sequence.fields.QuerySetSequenceModelField( + queryset=autocomplete.QuerySetSequence( + Article.objects.all(), + Event.objects.all(), + BasicPage.objects.all(), + Brief.objects.all(), + ), + required=False, + widget=dal_select2_queryset_sequence.widgets.QuerySetSequenceSelect2('dynamic-content-home-body'), + ) + + class Meta: + model = DynamicContentHomeBody + fields = ('__all__') diff --git a/app/organization/pages/migrations/0001_initial.py b/app/organization/pages/migrations/0001_initial.py new file mode 100644 index 00000000..aa7b7554 --- /dev/null +++ b/app/organization/pages/migrations/0001_initial.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-18 15:18 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('sites', '0002_alter_domain_unique'), + ] + + operations = [ + migrations.CreateModel( + name='DynamicContentHomeSlider', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('object_id', models.PositiveIntegerField(editable=False, null=True, verbose_name='related object')), + ('content_type', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', verbose_name='content type')), + ], + options={ + 'verbose_name': 'Dynamic Content Home Slider', + }, + ), + migrations.CreateModel( + name='Home', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('keywords_string', models.CharField(blank=True, editable=False, max_length=500)), + ('title', models.CharField(max_length=500, verbose_name='Title')), + ('slug', models.CharField(blank=True, help_text='Leave blank to have the URL auto-generated from the title.', max_length=2000, null=True, verbose_name='URL')), + ('_meta_title', models.CharField(blank=True, help_text='Optional title to be used in the HTML title tag. If left blank, the main title field will be used.', max_length=500, null=True, verbose_name='Title')), + ('description', models.TextField(blank=True, verbose_name='Description')), + ('gen_description', models.BooleanField(default=True, help_text='If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description.', verbose_name='Generate description')), + ('created', models.DateTimeField(editable=False, null=True)), + ('updated', models.DateTimeField(editable=False, null=True)), + ('status', models.IntegerField(choices=[(1, 'Draft'), (2, 'Published')], default=2, help_text='With Draft chosen, will only be shown for admin users on the site.', verbose_name='Status')), + ('publish_date', models.DateTimeField(blank=True, db_index=True, help_text="With Published chosen, won't be shown until this time", null=True, verbose_name='Published from')), + ('expiry_date', models.DateTimeField(blank=True, help_text="With Published chosen, won't be shown after this time", null=True, verbose_name='Expires on')), + ('short_url', models.URLField(blank=True, null=True)), + ('in_sitemap', models.BooleanField(default=True, verbose_name='Show in sitemap')), + ('site', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')), + ], + options={ + 'verbose_name': 'Home', + }, + ), + migrations.AddField( + model_name='dynamiccontenthomeslider', + name='home', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='organization-pages.Home', verbose_name='home'), + ), + ] diff --git a/app/organization/pages/migrations/0002_auto_20160818_1821.py b/app/organization/pages/migrations/0002_auto_20160818_1821.py new file mode 100644 index 00000000..001ed94c --- /dev/null +++ b/app/organization/pages/migrations/0002_auto_20160818_1821.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-18 16:21 +from __future__ import unicode_literals + +from django.db import migrations +import mezzanine.core.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('organization-pages', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='dynamiccontenthomeslider', + options={'ordering': ('_order',), 'verbose_name': 'Dynamic Content Home Slider'}, + ), + migrations.AddField( + model_name='dynamiccontenthomeslider', + name='_order', + field=mezzanine.core.fields.OrderField(null=True, verbose_name='Order'), + ), + ] diff --git a/app/organization/pages/migrations/0003_dynamiccontenthomebody.py b/app/organization/pages/migrations/0003_dynamiccontenthomebody.py new file mode 100644 index 00000000..c063e8c9 --- /dev/null +++ b/app/organization/pages/migrations/0003_dynamiccontenthomebody.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-08-18 16:55 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import mezzanine.core.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('organization-pages', '0002_auto_20160818_1821'), + ] + + operations = [ + migrations.CreateModel( + name='DynamicContentHomeBody', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('_order', mezzanine.core.fields.OrderField(null=True, verbose_name='Order')), + ('object_id', models.PositiveIntegerField(editable=False, null=True, verbose_name='related object')), + ('content_type', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', verbose_name='content type')), + ('home', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='organization-pages.Home', verbose_name='home')), + ], + options={ + 'ordering': ('_order',), + 'verbose_name': 'Dynamic Content Home Body', + }, + ), + ] diff --git a/app/organization/pages/migrations/__init__.py b/app/organization/pages/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/organization/pages/models.py b/app/organization/pages/models.py new file mode 100644 index 00000000..d6041086 --- /dev/null +++ b/app/organization/pages/models.py @@ -0,0 +1,25 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse, reverse_lazy +from mezzanine.core.models import Displayable, Slugged, Orderable +from organization.core.models import DynamicContent + + +class DynamicContentHomeSlider(DynamicContent, Orderable): + + home = models.ForeignKey("home", verbose_name=_('home'), blank=True, null=True, on_delete=models.SET_NULL) + + class Meta: + verbose_name = 'Dynamic Content Home Slider' + +class DynamicContentHomeBody(DynamicContent, Orderable): + + home = models.ForeignKey("home", verbose_name=_('home'), blank=True, null=True, on_delete=models.SET_NULL) + + class Meta: + verbose_name = 'Dynamic Content Home Body' + +class Home(Displayable): + + class Meta: + verbose_name = 'Home' diff --git a/app/organization/pages/tests.py b/app/organization/pages/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/app/organization/pages/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/organization/pages/translation.py b/app/organization/pages/translation.py new file mode 100644 index 00000000..6b678991 --- /dev/null +++ b/app/organization/pages/translation.py @@ -0,0 +1,19 @@ +from modeltranslation.translator import translator, register, TranslationOptions +from mezzanine.pages.models import Page, RichText +from mezzanine.pages.translation import TranslatedRichText +from organization.pages.models import * + +@register(Home) +class HomeTranslationOptions(TranslationOptions): + + pass + +@register(DynamicContentHomeSlider) +class DynamicContentHomeSliderOptions(TranslationOptions): + + pass + +@register(DynamicContentHomeBody) +class DynamicContentHomeBodyOptions(TranslationOptions): + + pass diff --git a/app/organization/pages/urls.py b/app/organization/pages/urls.py new file mode 100644 index 00000000..cd440ab6 --- /dev/null +++ b/app/organization/pages/urls.py @@ -0,0 +1,17 @@ +from __future__ import unicode_literals + +from django.conf.urls import patterns, include, url +from django.conf.urls.i18n import i18n_patterns +from django.contrib import admin + +from mezzanine.core.views import direct_to_template +from mezzanine.conf import settings +from organization.pages.views import DynamicContentHomeSliderView, DynamicContentHomeBodyView + +_slash = "/" if settings.APPEND_SLASH else "" + +urlpatterns = [ + url("^dynamic-content-home-slider/$", DynamicContentHomeSliderView.as_view(), name='dynamic-content-home-slider'), + url("^dynamic-content-home-body/$", DynamicContentHomeBodyView.as_view(), name='dynamic-content-home-body'), +] +'dynamic-content-home-body' diff --git a/app/organization/pages/views.py b/app/organization/pages/views.py new file mode 100644 index 00000000..c5227fc6 --- /dev/null +++ b/app/organization/pages/views.py @@ -0,0 +1,59 @@ +from django.shortcuts import render + +# Create your views here. +from dal import autocomplete +from dal_select2_queryset_sequence.views import Select2QuerySetSequenceView +from mezzanine_agenda.models import Event +from organization.core.models import BasicPage +from organization.magazine.models import Article, Topic, Brief + + +class DynamicContentHomeSliderView(Select2QuerySetSequenceView): + def get_queryset(self): + + articles = Article.objects.all() + basicpage = BasicPage.objects.all() + events = Event.objects.all() + + if self.q: + articles = articles.filter(title__icontains=self.q) + basicpage = basicpage.filter(title__icontains=self.q) + events = events.filter(title__icontains=self.q) + + qs = autocomplete.QuerySetSequence(articles, basicpage, events ) + + if self.q: + # This would apply the filter on all the querysets + qs = qs.filter(title__icontains=self.q) + + # This will limit each queryset so that they show an equal number + # of results. + qs = self.mixup_querysets(qs) + + return qs + +class DynamicContentHomeBodyView(Select2QuerySetSequenceView): + def get_queryset(self): + + articles = Article.objects.all() + basicpage = BasicPage.objects.all() + events = Event.objects.all() + briefs = Brief.objects.all() + + if self.q: + articles = articles.filter(title__icontains=self.q) + basicpage = basicpage.filter(title__icontains=self.q) + events = events.filter(title__icontains=self.q) + briefs = briefs.filter(title__icontains=self.q) + + qs = autocomplete.QuerySetSequence(articles, basicpage, events, briefs) + + if self.q: + # This would apply the filter on all the querysets + qs = qs.filter(title__icontains=self.q) + + # This will limit each queryset so that they show an equal number + # of results. + qs = self.mixup_querysets(qs) + + return qs diff --git a/app/organization/urls.py b/app/organization/urls.py index b8cfecb2..145430bd 100644 --- a/app/organization/urls.py +++ b/app/organization/urls.py @@ -13,6 +13,7 @@ from mezzanine.conf import settings urlpatterns = [ url("^", include('organization.core.urls')), + url("^", include('organization.pages.urls')), url("^", include('organization.featured.urls')), url("^", include('organization.festival.urls')), url("^", include('organization.magazine.urls')), diff --git a/app/settings.py b/app/settings.py index 0d44c21e..7cd057a3 100644 --- a/app/settings.py +++ b/app/settings.py @@ -227,6 +227,7 @@ INSTALLED_APPS = [ "mezzanine_agenda", # "orderable", "organization.core", + "organization.pages", "organization.team", "organization.festival", "organization.magazine",