Skip to content

Commit

Permalink
Make SEO objects depend on the site too
Browse files Browse the repository at this point in the history
If you have several sites in your Django portal, then you'll have
one SEO metadata object per path, language and site combination
  • Loading branch information
ablanco committed Jan 3, 2017
1 parent 24865c3 commit 62b813c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 39 deletions.
15 changes: 8 additions & 7 deletions painlessseo/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def clean(self):
obj = cleaned_data.get('id')
for lang, fields in settings.SEO_ADMIN_FORM_REQUIRED_FIELDS.items():
if obj.lang_code == lang:
cleaned_data = self.validate_required_fields(cleaned_data, fields)
cleaned_data = self.validate_required_fields(cleaned_data,
fields)
return cleaned_data


Expand All @@ -51,8 +52,8 @@ class SeoMetadataInline(GenericStackedInline):
max_num = 0
model = SeoMetadata

fields = ('language', 'title', 'description')
readonly_fields = ('language', )
fields = ('language', 'site', 'title', 'description')
readonly_fields = ('language', 'site', )

def has_delete_permission(self, request, obj=None):
return False
Expand All @@ -67,13 +68,13 @@ class SeoMetadataWithValidationInline(SeoMetadataInline):


class SeoMetadataAdmin(admin.ModelAdmin):
list_display = ('path', 'lang_code', )
list_display = ('path', 'lang_code', 'site', )
search_fields = ['path', ]
list_filter = ('lang_code', )
list_filter = ('lang_code', 'site', )
exclude = ('content_type', 'object_id', )

fields = ('language', 'title', 'description')
readonly_fields = ('language', )
fields = ('language', 'site', 'title', 'description', )
readonly_fields = ('language', 'site', )

def language(self, obj):
return get_language(obj)
Expand Down
4 changes: 4 additions & 0 deletions painlessseo/locale/es/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ msgstr "Descripción"
#: models.py:24 models.py:25
msgid "SEO metadata"
msgstr "SEO metadatos"

#: models.py:45
msgid "Site"
msgstr "Sitio"
83 changes: 53 additions & 30 deletions painlessseo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
except:
from django.contrib.contenttypes.generic import GenericForeignKey

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.utils.translation import activate, get_language
Expand All @@ -16,57 +17,79 @@


class SeoMetadata(models.Model):
content_type = models.ForeignKey(ContentType, null=True, blank=True)
object_id = models.PositiveIntegerField(null=True, blank=True)
content_object = GenericForeignKey('content_type', 'object_id')
path = models.CharField(verbose_name=_('Path'), max_length=200, db_index=True,
help_text=_("This should be an absolute path, excluding the domain name. Example: '/foo/bar/'."))
lang_code = models.CharField(verbose_name=_('Language'), max_length=2,
choices=settings.SEO_LANGUAGES,
default=settings.DEFAULT_LANG_CODE)
title = models.CharField(verbose_name=_('Title'), max_length=68, blank=True)
description = models.CharField(verbose_name=_('Description'), max_length=155, blank=True)
content_type = models.ForeignKey(
ContentType, null=True, blank=True)

object_id = models.PositiveIntegerField(
null=True, blank=True)

content_object = GenericForeignKey(
'content_type', 'object_id')

path = models.CharField(
verbose_name=_('Path'), max_length=200, db_index=True,
help_text=_('This should be an absolute path, excluding the domain '
'name. Example: \'/foo/bar/\'.'))

lang_code = models.CharField(
verbose_name=_('Language'), max_length=2,
choices=settings.SEO_LANGUAGES, default=settings.DEFAULT_LANG_CODE)

title = models.CharField(
verbose_name=_('Title'), max_length=68, blank=True)

description = models.CharField(
verbose_name=_('Description'), max_length=155, blank=True)

site = models.ForeignKey(
Site, verbose_name=_('Site'), related_name='seo_metadata', null=True,
blank=True, default=None)

class Meta:
verbose_name = _('SEO metadata')
verbose_name_plural = _('SEO metadata')
db_table = 'seo_metadata'
unique_together = (('path', 'lang_code'), )
ordering = ('path', 'lang_code')
unique_together = (('path', 'lang_code', 'site'), )
ordering = ('path', 'lang_code', 'site')

def __unicode__(self):
return "Language: %s | URL: %s" % (self.lang_code, self.path)


def update_seo(sender, instance, **kwargs):
active_lang = get_language()
sites = Site.objects.all()
for lang_code, lang_name in settings.SEO_LANGUAGES:
activate(lang_code)
try:
sm = SeoMetadata.objects.get(
content_type=ContentType.objects.get_for_model(instance),
object_id=instance.id, lang_code=lang_code)
if instance.get_absolute_url() != sm.path:
sm.path = instance.get_absolute_url()
except SeoMetadata.DoesNotExist:
sm = SeoMetadata(
lang_code=lang_code, content_object=instance,
path=instance.get_absolute_url())
sm.save()
for site in sites:
try:
sm = SeoMetadata.objects.get(
content_type=ContentType.objects.get_for_model(instance),
object_id=instance.id, lang_code=lang_code, site=site)
if instance.get_absolute_url() != sm.path:
sm.path = instance.get_absolute_url()
except SeoMetadata.DoesNotExist:
sm = SeoMetadata(
lang_code=lang_code, content_object=instance,
path=instance.get_absolute_url(), site=site)
sm.save()
activate(active_lang)


def delete_seo(sender, instance, **kwargs):
ctype = ContentType.objects.get_for_model(instance)
for sm in SeoMetadata.objects.filter(content_type=ctype, object_id=instance.id):
sm.delete()
SeoMetadata.objects.filter(
content_type=ctype, object_id=instance.id).delete()


def register_seo_signals():
for app, model in settings.SEO_MODELS:
ctype = ContentType.objects.get(app_label=app, model=model)
if not hasattr(ctype.model_class(), 'get_absolute_url'):
raise ImproperlyConfigured("Needed 'get_absolute_url' method not "
"defined on '%s.%s' model." % (app, model))
models.signals.post_save.connect(update_seo, sender=ctype.model_class(), weak=False)
models.signals.pre_delete.connect(delete_seo, sender=ctype.model_class(), weak=False)
raise ImproperlyConfigured(
'Needed \'get_absolute_url\' method not defined on \'%s.%s\' '
'model.' % (app, model))
models.signals.post_save.connect(
update_seo, sender=ctype.model_class(), weak=False)
models.signals.pre_delete.connect(
delete_seo, sender=ctype.model_class(), weak=False)
3 changes: 2 additions & 1 deletion painlessseo/templates/painlessseo/metadata.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% load seo %}

<title>{{title}}</title>
{% with description|single_quotes as safer_description %}
<meta name="description" content="{{safer_description|safe}}">
<meta name="description" content="{{safer_description|safe}}">
{% endwith %}
5 changes: 4 additions & 1 deletion painlessseo/templatetags/seo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (C) 2014 Glamping Hub (https://glampinghub.com)
# License: BSD 3-Clause

from django.contrib.sites.models import Site
from django.forms.models import model_to_dict
from django.template import Library
from django.utils.translation import get_language
Expand All @@ -24,9 +25,11 @@ def get_seo(context, **kwargs):
request = context['request']
path = request.path
lang_code = get_language()[:2]
site = Site.objects.get_current()
try:
metadata = model_to_dict(SeoMetadata.objects.get(path=path,
lang_code=lang_code))
lang_code=lang_code,
site=site))
except SeoMetadata.DoesNotExist:
metadata = {}
result = {}
Expand Down

0 comments on commit 62b813c

Please # to comment.