Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canonical sites for photos and galleries https://github.com/jdriscoll/django-photologue/issues/135 #136

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
43 changes: 39 additions & 4 deletions photologue/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ class Meta:
if MULTISITE:
exclude = []
else:
exclude = ['sites']
exclude = ['sites', 'canonical_site']


class GalleryAdmin(admin.ModelAdmin):
list_display = ('title', 'date_added', 'photo_count', 'is_public')
list_filter = ['date_added', 'is_public']
if MULTISITE:
list_filter.append('sites')
list_filter.extend(('sites', 'canonical_site'))
date_hierarchy = 'date_added'
prepopulated_fields = {'slug': ('title',)}
form = GalleryAdminForm
Expand All @@ -51,6 +51,12 @@ def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs["initial"] = [Site.objects.get_current()]
return super(GalleryAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

def formfield_for_foreignkey(self, db_field, request, **kwargs):
""" Set the current site as initial value. """
if db_field.name == "canonical_site":
kwargs["initial"] = Site.objects.get_current()
return super(GalleryAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

def save_related(self, request, form, *args, **kwargs):
"""
If the user has saved a gallery with a photo that belongs only to
Expand All @@ -67,6 +73,13 @@ def save_related(self, request, form, *args, **kwargs):
len(orphaned_photos)
) % {'photo_list': ", ".join([photo.title for photo in orphaned_photos])}
messages.warning(request, msg)
if form.instance.canonical_site and not form.instance.sites.filter(
pk=form.instance.canonical_site.pk).exists():
msg = 'The canonical site is not in sites, it will appear '\
'in the %s sitemap but the link will be a 404' %\
form.instance.canonical_site
messages.warning(request, msg)


def add_to_current_site(modeladmin, request, queryset):
current_site = Site.objects.get_current()
Expand Down Expand Up @@ -140,15 +153,15 @@ class Meta:
if MULTISITE:
exclude = []
else:
exclude = ['sites']
exclude = ['sites', 'canonical_site']


class PhotoAdmin(admin.ModelAdmin):
list_display = ('title', 'date_taken', 'date_added',
'is_public', 'view_count', 'admin_thumbnail')
list_filter = ['date_added', 'is_public']
if MULTISITE:
list_filter.append('sites')
list_filter.extend(('sites', 'canonical_site'))
search_fields = ['title', 'slug', 'caption']
list_per_page = 10
prepopulated_fields = {'slug': ('title',)}
Expand All @@ -164,6 +177,28 @@ def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs["initial"] = [Site.objects.get_current()]
return super(PhotoAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

def formfield_for_foreignkey(self, db_field, request, **kwargs):
""" Set the current site as initial value. """
if db_field.name == "canonical_site":
kwargs["initial"] = Site.objects.get_current()
return super(PhotoAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)


def save_related(self, request, form, *args, **kwargs):
"""
If the user has saved a photo that is in a sitemap but not actually on the site,
Let them know
"""
super(PhotoAdmin, self).save_related(request, form, *args, **kwargs)
if form.instance.canonical_site and not form.instance.sites.filter(
pk=form.instance.canonical_site.pk).exists():

msg = _('The canonical site is not in sites, it will appear '
'in the %s sitemap but the link will be a 404'
% form.instance.canonical_site)
messages.warning(request, msg)


def add_photos_to_current_site(modeladmin, request, queryset):
current_site = Site.objects.get_current()
current_site.photo_set.add(*queryset)
Expand Down
4 changes: 4 additions & 0 deletions photologue/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ def on_site(self):
"""Return objects linked to the current site only."""
return self.filter(sites__id=settings.SITE_ID)

def canonical_on_site(self):
"""Return objects canonical to the current site only."""
return self.filter(canonical_site__id=settings.SITE_ID)


class GalleryQuerySet(SharedQueries, QuerySet):
pass
Expand Down
27 changes: 27 additions & 0 deletions photologue/migrations/0009_auto_20150603_1132.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('sites', '0001_initial'),
('photologue', '0008_auto_20150509_1557'),
]

operations = [
migrations.AddField(
model_name='gallery',
name='canonical_site',
field=models.ForeignKey(related_name='photologue_gallery_canonical_related', verbose_name='canonical site', blank=True, to='sites.Site', null=True),
preserve_default=True,
),
migrations.AddField(
model_name='photo',
name='canonical_site',
field=models.ForeignKey(related_name='photologue_photo_canonical_related', verbose_name='canonical site', blank=True, to='sites.Site', null=True),
preserve_default=True,
),
]
29 changes: 29 additions & 0 deletions photologue/migrations/0010_auto_20150604_0102.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings
from django.contrib.sites.models import Site

MULTISITE = getattr(settings, 'PHOTOLOGUE_MULTISITE', False)

def set_canonical_non_multisite(apps, schema_editor):
Gallery = apps.get_model("photologue", "Gallery")
Photo = apps.get_model("photologue", "Photo")
if not MULTISITE:
current_site = Site.objects.first()
Gallery.objects.update(canonical_site=current_site)
Photo.objects.update(canonical_site=current_site)

#Do we need to do anything for not multisite?


class Migration(migrations.Migration):

dependencies = [
('photologue', '0009_auto_20150603_1132'),
]

operations = [
migrations.RunPython(set_canonical_non_multisite),
]
22 changes: 21 additions & 1 deletion photologue/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,11 @@ class Gallery(models.Model):
blank=True)
sites = models.ManyToManyField(Site, verbose_name=_(u'sites'),
blank=True)

canonical_site = models.ForeignKey(Site, verbose_name=_(u'canonical site'),
related_name="%(app_label)s_%(class)s_canonical_related",
blank=True, null=True,
help_text=_('The "Canonical Site" is the site that'
' will appear in your sitemaps'))
objects = GalleryQuerySet.as_manager()

class Meta:
Expand All @@ -208,6 +212,10 @@ def __str__(self):
def get_absolute_url(self):
return reverse('photologue:pl-gallery', args=[self.slug])

def get_canonical_url(self):
url = reverse('photologue:pl-gallery', args=[self.slug])
return "http://%s%s" % (self.canonical_site.domain, url)

def latest(self, limit=LATEST_LIMIT, public=True):
if not limit:
limit = self.photo_count()
Expand Down Expand Up @@ -529,6 +537,12 @@ class Photo(ImageModel):
help_text=_('Public photographs will be displayed in the default views.'))
sites = models.ManyToManyField(Site, verbose_name=_(u'sites'),
blank=True)
canonical_site = models.ForeignKey(Site, verbose_name=_(u'canonical site'),
related_name="%(app_label)s_%(class)s_canonical_related",
blank=True, null=True,
help_text=_('The "Canonical Site" is the site that'
' will appear in your sitemaps'))


objects = PhotoQuerySet.as_manager()

Expand All @@ -549,6 +563,11 @@ def save(self, *args, **kwargs):
def get_absolute_url(self):
return reverse('photologue:pl-photo', args=[self.slug])

def get_canonical_url(self):
url = reverse('photologue:pl-photo', args=[self.slug])
return "http://%s%s" % (self.canonical_site.domain, url)


def public_galleries(self):
"""Return the public galleries to which this photo belongs."""
return self.galleries.filter(is_public=True)
Expand Down Expand Up @@ -899,5 +918,6 @@ def add_default_site(instance, created, **kwargs):
if instance.sites.exists():
return
instance.sites.add(Site.objects.get_current())
instance.canonical_site = Site.objects.get_current()
post_save.connect(add_default_site, sender=Gallery)
post_save.connect(add_default_site, sender=Photo)
4 changes: 2 additions & 2 deletions photologue/sitemaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class GallerySitemap(Sitemap):
def items(self):
# The following code is very basic and will probably cause problems with
# large querysets.
return Gallery.objects.on_site().is_public()
return Gallery.objects.canonical_on_site().is_public()

def lastmod(self, obj):
return obj.date_added
Expand All @@ -48,7 +48,7 @@ class PhotoSitemap(Sitemap):
def items(self):
# The following code is very basic and will probably cause problems with
# large querysets.
return Photo.objects.on_site().is_public()
return Photo.objects.canonical_on_site().is_public()

def lastmod(self, obj):
return obj.date_added
6 changes: 4 additions & 2 deletions photologue/tests/test_sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ def setUp(self):

with self.settings(PHOTOLOGUE_MULTISITE=True):
# Be explicit about linking Galleries/Photos to Sites."""
self.gallery1 = GalleryFactory(slug='test-gallery', sites=[self.site1])
self.gallery1 = GalleryFactory(slug='test-gallery', sites=[self.site1],
canonical_site=self.site1)
self.gallery2 = GalleryFactory(slug='not-on-site-gallery')
self.photo1 = PhotoFactory(slug='test-photo', sites=[self.site1])
self.photo1 = PhotoFactory(slug='test-photo', sites=[self.site1],
canonical_site=self.site1)
self.photo2 = PhotoFactory(slug='not-on-site-photo')
self.gallery1.photos.add(self.photo1, self.photo2)

Expand Down