Another Step in the Quest to clean up the code base.

This commit is contained in:
2017-09-08 07:19:50 +02:00
parent 8f4bdec701
commit 6e2240ed5f
229 changed files with 1915 additions and 15175 deletions

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from ckeditor.fields import RichTextField
""" Django Models for a lightwight Content Management."""
from ckeditor_uploader.fields import RichTextUploadingField
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ValidationError
@@ -12,23 +12,29 @@ from django.utils.translation import get_language, ugettext as _
from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, CLEANER
DJANGO_VIEW = 0
HTML_PAGE = 1
PDF_PAGE = 2
CONTENT_CHOICES = (
(0, u'Django View'),
(1, u'HTML'),
(2, u'PDF')
(DJANGO_VIEW, u'Django View'),
(HTML_PAGE, u'HTML'),
(PDF_PAGE, u'PDF')
)
CONTENT_TYPE_EXTENSIONS = {
DJANGO_VIEW: "/",
HTML_PAGE: ".html",
PDF_PAGE: ".pdf"
}
def get_upload_path(instance, filename):
"""
Generates the desired file path and filename for an uploaded Image.
"""Generates the desired file path and filename for an uploaded Image.
With this function Django can save the uploaded images to subfolders that
also have a meaning for humans.
@param instance: an Django Object for which the Image has been uploaded.
@type instance: a instace of an models.Model sub-class.
@param filename: The filename of the uploaded image.
@type filename: String
:param instance: an Django Object for which the Image has been uploaded.
:param filename: The filename of the uploaded image.
:return: relative path and filename for the image on the server.
"""
extension = filename[filename.rfind('.') + 1:]
if isinstance(instance, Category):
@@ -36,11 +42,20 @@ def get_upload_path(instance, filename):
class ArticleManager(models.Manager):
"""Adds some predifined querys and joins some tables for faster querys."""
def get_queryset(self):
"""Join the author and category to the default query for more
perfomance.
:return: QuerySet"""
return super(ArticleManager, self).get_queryset().select_related(
'author', 'category')
def published(self):
"""Return articles that has been published by now.
:return: QuerySet"""
return self.filter(
status=STATUS_PUBLISHED,
date_created__lte=timezone.now()
@@ -48,10 +63,12 @@ class ArticleManager(models.Manager):
class Article(models.Model):
"""A news article, simmilar to an blog entry, it can be in german and
english."""
headline_de = models.CharField(_('Headline'), max_length=255)
headline_en = models.CharField('Headline', max_length=255, blank=True)
content_de = RichTextField(_('Content'))
content_en = RichTextField('Content', blank=True)
content_de = RichTextUploadingField(_('Content'))
content_en = RichTextUploadingField('Content', blank=True)
category = models.ForeignKey('Category', verbose_name=_('Category'))
image = models.ImageField(_('Image'), upload_to='news/',
blank=True, null=True)
@@ -65,11 +82,13 @@ class Article(models.Model):
objects = ArticleManager()
class Meta(object):
"""Sort them by creation date, newes articles first."""
verbose_name = _('Article')
verbose_name_plural = _('Articles')
ordering = ('-date_created',)
def clean(self):
"""Give the article an slug and scrub the html code."""
if not self.date_created:
self.date_created = timezone.now()
if not self.slug:
@@ -78,48 +97,78 @@ class Article(models.Model):
self.content_en = CLEANER.clean_html(self.content_en)
def __str__(self):
"""Returns the headline of this article."""
return self.headline
@property
def get_image(self):
if self.image:
return self.image
else:
return self.category.image
"""Return the article image, or the category image if unset."""
return self.image if self.image else self.category.image
def get_absolute_url(self):
kwargs = {
'year': self.date_created.strftime('%Y'),
'month': self.date_created.strftime('%m'),
'slug': self.slug,
}
return reverse('show-article', kwargs=kwargs)
"""return the absolute URL for this article."""
return reverse('show-article',
kwargs={'year': self.date_created.strftime('%Y'),
'month': self.date_created.strftime('%m'),
'slug': self.slug})
@property
def headline(self):
headline = getattr(self, "headline_%s" % get_language())
if not headline:
return mark_safe(self.headline_de)
else:
return mark_safe(headline)
"""Return the localized headline, fallback to german if necessary."""
return mark_safe(
getattr(self, "headline_%s" % get_language(), self.headline_de)
)
@property
def content(self):
content = getattr(self, "content_%s" % get_language(), self.content_de)
if not content:
return mark_safe(self.content_de)
else:
return mark_safe(content)
"""Return the localized content, fallback to german if necessary."""
return mark_safe(
getattr(self, "content_%s" % get_language(), self.content_de)
)
class Category(models.Model):
"""A news category, articles will be assicuated with it."""
name_de = models.CharField(_('Name'), max_length=80)
name_en = models.CharField(_('Name'), max_length=80, blank=True)
description_de = models.TextField(_('Description'))
description_en = models.TextField(_('Description'), blank=True)
image = models.ImageField(_('Image'), upload_to='news/categories/',
blank=True, null=True)
slug = models.SlugField(_('Slug'), unique=True, db_index=True)
class Meta(object):
"""Set default the ordering."""
ordering = ('slug',)
verbose_name = _('Category')
verbose_name_plural = _('Categories')
@property
def name(self):
"""Return the localized name, fallback to german if necessary."""
return getattr(self, "name_%s" % get_language(), self.name_de)
@property
def description(self):
"""Return the localized description, fallback to german if necessary."""
return getattr(self, "description_%s" % get_language(),
self.description_de)
def get_absolute_url(self):
"""Return the URL of the article archive, filtered on this category."""
return reverse('article-archive', kwargs={'category': self.slug})
def __str__(self):
"""Return the localized name, fallback to german if necessary."""
return self.name
class Page(models.Model):
"""
Eine Seite auf der Homepage. Sie kann eine "statische" HTML Seite,
die URL einer dynamische Django View, oder ein PDF Dokument sein.
Jede Seite kann neben Deutsch auch auf Englisch angeboten werden.
Ist keine englische Übersetzung vorhanden, wird die deutsche Version
angeboten.
"""
"""A page on this homepage. It can have a "static" HTML page, the URL of a
dynamic Django view, or a PDF document.
Each page can be offered in German and English. If no English translation
is available, the German version will be displayed."""
menu_name_de = models.CharField(
max_length=255,
@@ -180,8 +229,8 @@ class Page(models.Model):
content_type = models.IntegerField(
choices=CONTENT_CHOICES,
verbose_name=_('content type'))
content_de = RichTextField('Inhalt', blank=True)
content_en = RichTextField('Content', blank=True)
content_de = RichTextUploadingField('Inhalt', blank=True)
content_en = RichTextUploadingField('Content', blank=True)
enable_comments = models.BooleanField(
default=True,
verbose_name=_('enable comments')
@@ -206,43 +255,46 @@ class Page(models.Model):
)
def __str__(self):
return u'%s' % self.title
"""Return the localized title, fallback to german if necessary."""
return self.title
@property
def content(self):
cont = getattr(self, "content_%s" % get_language()) or self.content_de
return mark_safe(cont)
"""Return the localized content, fallback to german if necessary."""
return mark_safe(
getattr(self, "content_%s" % get_language(), self.content_de)
)
@property
def css_class(self):
"""Returns the name of the content typ of this page as a CSS class.
This allows easy styling of page links, depending on the content type.
"""
return CONTENT_CHOICES[self.content_type][1].lower().replace(' ', '_')
@property
def description(self):
lang_attr = "description_%s" % get_language()
return getattr(self, lang_attr, self.description_de)
"""Return the localized description, fallback to german if necessary."""
return getattr(self, "description_%s" % get_language(),
self.description_de)
@property
def menu_name(self):
lang_attr = "menu_name_%s" % get_language()
return getattr(self, lang_attr, self.menu_name_de)
"""Return the localized menu name, fallback to german if necessary."""
return getattr(self, "menu_name_%s" % get_language(), self.menu_name_de)
@property
def pdf_file(self):
lang_attr = "pdf_%s" % get_language()
return getattr(self, lang_attr, self.pdf_de)
"""Return the localized PDF file, fallback to german if necessary."""
return getattr(self, "pdf_%s" % get_language(), self.pdf_de)
@property
def title(self):
""" Return the translated title if available """
lang_attr = "title_%s" % get_language()
return getattr(self, lang_attr, self.title_de)
"""Return the localized title, fallback to german if necessary."""
return getattr(self, "title_%s" % get_language(), self.title_de)
def clean(self):
"""
:return:
"""
"""set the URL path, the right content type, and scrub the HTML code."""
if self.parent is None:
self.path = self.slug
else:
@@ -251,7 +303,7 @@ class Page(models.Model):
if self.content_type is None:
if self.pdf_de:
self.content_type = 2
if self.content_de:
elif self.content_de:
self.content_type = 1
else:
self.content_type = 0
@@ -263,53 +315,23 @@ class Page(models.Model):
_(u'Please upload a PDF-File to this PDF-Page.'))
def get_absolute_url(self):
aboslute_url = '/' + self.path
if self.content_type == 1:
aboslute_url += '.html'
elif self.content_type == 2:
aboslute_url += '.pdf'
else:
aboslute_url += '/'
return aboslute_url
"""Return the path with an extension that matches the content type.
It's useful for an user to match the URL to the contenttype.
:return: sting with the absolute URL of this page."""
return '/' + self.path + CONTENT_TYPE_EXTENSIONS[self.content_type]
class Meta(object):
"""Set default ordering and an unique priamry key to avoid dupes."""
ordering = ['parent__id', 'position']
unique_together = (('slug', 'parent'),)
verbose_name = _('Page')
verbose_name_plural = _('Pages')
class Category(models.Model):
name_de = models.CharField(_('Name'), max_length=80)
name_en = models.CharField(_('Name'), max_length=80, blank=True)
description_de = models.TextField(_('Description'))
description_en = models.TextField(_('Description'), blank=True)
image = models.ImageField(_('Image'), upload_to='news/categories/',
blank=True, null=True)
slug = models.SlugField(_('Slug'), unique=True, db_index=True)
class Meta(object):
ordering = ('slug',)
verbose_name = _('Category')
verbose_name_plural = _('Categories')
@property
def name(self):
return getattr(self, "name_%s" % get_language(), self.name_de)
@property
def description(self):
return getattr(self, "description_%s" % get_language(),
self.description_de)
def get_absolute_url(self):
return reverse('article-archive', kwargs={'category': self.slug})
def __str__(self):
return self.name
def force_cache_update(sender, instance, **kwargs):
def force_cache_update(sender, instance, **kwargs): # Ignore PyLintBear (W0613)
"""A Django signal to trigger the save() method on all subpages to catch
possible URL changes and invalidate the cache."""
for page in instance.subpages.all():
page.clean()
page.save()