From aaa37025082bb78ca6fb7ca0ed75695de5847f83 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Thu, 30 Aug 2012 15:39:35 +0200 Subject: [PATCH] fixes #2360: allow empty slugs for non-published entries --- migdal/fields.py | 25 +++++++ ..._entry_slug_pl__chg_field_entry_slug_en.py | 74 +++++++++++++++++++ migdal/models.py | 17 +++-- prawokultury/templates/404.html | 2 +- 4 files changed, 110 insertions(+), 8 deletions(-) create mode 100755 migdal/fields.py create mode 100644 migdal/migrations/0004_auto__chg_field_entry_slug_pl__chg_field_entry_slug_en.py diff --git a/migdal/fields.py b/migdal/fields.py new file mode 100755 index 0000000..843c44e --- /dev/null +++ b/migdal/fields.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# +from django.db import models + +class SlugNullField(models.SlugField): + description = "SlugField that stores NULL instead of blank value." + + def to_python(self, value, **kwargs): + value = super(SlugNullField, self).to_python(value, **kwargs) + return value if value is not None else u"" + + def get_prep_value(self, value, **kwargs): + value = super(SlugNullField, self).get_prep_value(value, **kwargs) + return value or None + + +try: + # check for south + from south.modelsinspector import add_introspection_rules +except ImportError: + pass +else: + add_introspection_rules([], ["^migdal\.fields\.SlugNullField"]) diff --git a/migdal/migrations/0004_auto__chg_field_entry_slug_pl__chg_field_entry_slug_en.py b/migdal/migrations/0004_auto__chg_field_entry_slug_pl__chg_field_entry_slug_en.py new file mode 100644 index 0000000..a546e52 --- /dev/null +++ b/migdal/migrations/0004_auto__chg_field_entry_slug_pl__chg_field_entry_slug_en.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'Entry.slug_pl' + db.alter_column('migdal_entry', 'slug_pl', self.gf('migdal.fields.SlugNullField')(max_length=50, unique=True, null=True)) + + # Changing field 'Entry.slug_en' + db.alter_column('migdal_entry', 'slug_en', self.gf('migdal.fields.SlugNullField')(max_length=50, unique=True, null=True)) + + def backwards(self, orm): + + # Changing field 'Entry.slug_pl' + db.alter_column('migdal_entry', 'slug_pl', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50, null=True)) + + # Changing field 'Entry.slug_en' + db.alter_column('migdal_entry', 'slug_en', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50, null=True)) + + models = { + 'migdal.attachment': { + 'Meta': {'object_name': 'Attachment'}, + 'entry': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['migdal.Entry']"}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'migdal.category': { + 'Meta': {'object_name': 'Category'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug_en': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}), + 'slug_pl': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}), + 'taxonomy': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'title_en': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64', 'db_index': 'True'}), + 'title_pl': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64', 'db_index': 'True'}) + }, + 'migdal.entry': { + 'Meta': {'ordering': "['-date']", 'object_name': 'Entry'}, + '_body_en_rendered': ('django.db.models.fields.TextField', [], {}), + '_body_pl_rendered': ('django.db.models.fields.TextField', [], {}), + '_lead_en_rendered': ('django.db.models.fields.TextField', [], {}), + '_lead_pl_rendered': ('django.db.models.fields.TextField', [], {}), + 'author': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'author_email': ('django.db.models.fields.EmailField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'body_en': ('markupfield.fields.MarkupField', [], {'null': 'True', 'rendered_field': 'True', 'blank': 'True'}), + 'body_en_markup_type': ('django.db.models.fields.CharField', [], {'default': "'textile_pl'", 'max_length': '30', 'blank': 'True'}), + 'body_pl': ('markupfield.fields.MarkupField', [], {'null': 'True', 'rendered_field': 'True', 'blank': 'True'}), + 'body_pl_markup_type': ('django.db.models.fields.CharField', [], {'default': "'textile_pl'", 'max_length': '30', 'blank': 'True'}), + 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['migdal.Category']", 'null': 'True', 'blank': 'True'}), + 'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'lead_en': ('markupfield.fields.MarkupField', [], {'null': 'True', 'rendered_field': 'True', 'blank': 'True'}), + 'lead_en_markup_type': ('django.db.models.fields.CharField', [], {'default': "'textile_pl'", 'max_length': '30', 'blank': 'True'}), + 'lead_pl': ('markupfield.fields.MarkupField', [], {'null': 'True', 'rendered_field': 'True', 'blank': 'True'}), + 'lead_pl_markup_type': ('django.db.models.fields.CharField', [], {'default': "'textile_pl'", 'max_length': '30', 'blank': 'True'}), + 'needed_en': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1', 'db_index': 'True'}), + 'promo': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'published_en': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'published_pl': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'slug_en': ('migdal.fields.SlugNullField', [], {'max_length': '50', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'slug_pl': ('migdal.fields.SlugNullField', [], {'max_length': '50', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'title_en': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'title_pl': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}) + } + } + + complete_apps = ['migdal'] \ No newline at end of file diff --git a/migdal/models.py b/migdal/models.py index 6ba28ee..e3f7819 100644 --- a/migdal/models.py +++ b/migdal/models.py @@ -4,6 +4,7 @@ # from django.conf import settings from django.contrib.sites.models import Site +from django.core.exceptions import ValidationError from django.core.mail import send_mail from django.db import models from django.template import loader, Context @@ -12,6 +13,7 @@ from django_comments_xtd.models import XtdComment from markupfield.fields import MarkupField from migdal import app_settings from migdal.helpers import add_translatable +from migdal.fields import SlugNullField class Category(models.Model): taxonomy = models.CharField(_('taxonomy'), max_length=32, @@ -65,14 +67,15 @@ class Entry(models.Model): published_now = True if published_now: self.notify_author_published() - - # convert blank to null for slug uniqueness check to work - for lc, ln in app_settings.OPTIONAL_LANGUAGES: - slug_name = "slug_%s" % lc - if hasattr(self, slug_name) == u'': - setattr(self, slug_name, None) super(Entry, self).save(*args, **kwargs) + def clean(self): + for lc, ln in settings.LANGUAGES: + if (getattr(self, "published_%s" % lc) and + not getattr(self, "slug_%s" % lc)): + raise ValidationError( + ugettext("Published entry should have a slug in relevant language (%s).") % lc) + @models.permalink def get_absolute_url(self): return ('migdal_entry_%s' % self.type, [self.slug]) @@ -104,7 +107,7 @@ add_translatable(Entry, languages=app_settings.OPTIONAL_LANGUAGES, fields={ }) add_translatable(Entry, { - 'slug': models.SlugField(unique=True, db_index=True, null=True, blank=True), + 'slug': SlugNullField(unique=True, db_index=True, null=True, blank=True), 'title': models.CharField(_('title'), max_length=255, null=True, blank=True), 'lead': MarkupField(_('lead'), markup_type='textile_pl', null=True, blank=True, help_text=_('Use Textile syntax.')), diff --git a/prawokultury/templates/404.html b/prawokultury/templates/404.html index 879d30d..62bbbe8 100755 --- a/prawokultury/templates/404.html +++ b/prawokultury/templates/404.html @@ -2,7 +2,7 @@ {% load i18n %} -{% block "titleextra" %}{% trans "Page not found." %}{% endblock %} +{% block "titleextra" %}{% trans "Page not found" %} :: {% endblock %} {% block "body" %} -- 2.20.1