Skip to content

Commit 8467a50

Browse files
authored
Place sponsors logos via templatetag (#1822)
* New manager method to filter by enabled sponsorships * New manager method to filter by sponsorships with logo placement benefits * New template tag to list sponsors accordingly with logo placement rules * Replace box for download sponsors by new template tag * Change sponsors URL to be a TemplateView instead of SiteTree * Display sponsors logos * Replace references from master branch to new main one * Enable search by sponsor name * Make sure title is still the same * Move tests for admin views to a specific test file * Create form to list related sponsorships from a specific benefit * Implement admin view to update related sponsor benefit from a sponsorships benefit * Add select/clear all sponsorships helper * Disable new sponsor logo placement by default * Fix CSS class name * Refactor to group sponsorships by package in the backend * Template tag have to know how to control logos dimension * Display logos as thumbnail instead of using the uploaded logo * Display logos at sponsorship detail page as thumbnails as well
1 parent 33247f7 commit 8467a50

25 files changed

+1205
-620
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# python.org
22

3-
[![Build Status](https://travis-ci.org/python/pythondotorg.svg?branch=master)](https://travis-ci.org/python/pythondotorg)
3+
[![Build Status](https://travis-ci.org/python/pythondotorg.svg?branch=main)](https://travis-ci.org/python/pythondotorg)
44
[![Documentation Status](https://readthedocs.org/projects/pythondotorg/badge/?version=latest)](https://pythondotorg.readthedocs.io/?badge=latest)
55

66
### General information
@@ -19,5 +19,5 @@ https://bugs.python.org.
1919
* Documentation: https://pythondotorg.readthedocs.org/
2020
* Mailing list: [pydotorg-www](https://mail.python.org/mailman/listinfo/pydotorg-www)
2121
* IRC: `#pydotorg` on Freenode
22-
* Staging site: https://staging.python.org/ (`master` branch)
22+
* Staging site: https://staging.python.org/ (`main` branch)
2323
* License: Apache License

base-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ xhtml2pdf==0.2.5
4444
django-easy-pdf==0.1.1
4545
num2words==0.5.10
4646
django-polymorphic==2.1.2
47+
sorl-thumbnail==12.7.0

docs/source/contributing.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ maintainers if you follow good coding practices such as:
2828
methods behind your change
2929

3030
.. _GitHub: https://github.com/python/pythondotorg/issues
31-
.. _license: https://github.com/python/pythondotorg/blob/master/LICENSE
31+
.. _license: https://github.com/python/pythondotorg/blob/main/LICENSE
3232
.. _pythondotorg: https://github.com/python/pythondotorg

docs/source/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ General information
1010
:Issue tracker: https://github.com/python/pythondotorg/issues
1111
:Mailing list: pydotorg-www_
1212
:IRC: ``#pydotorg`` on Freenode
13-
:Staging site: https://staging.python.org/ (``master`` branch)
13+
:Staging site: https://staging.python.org/ (``main`` branch)
1414
:Production configuration: https://github.com/python/psf-salt
1515
:Travis:
16-
.. image:: https://travis-ci.org/python/pythondotorg.svg?branch=master
16+
.. image:: https://travis-ci.org/python/pythondotorg.svg?branch=main
1717
:target: https://travis-ci.org/python/pythondotorg
1818
:License: Apache License
1919

pydotorg/settings/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
'widget_tweaks',
158158
'django_countries',
159159
'easy_pdf',
160+
'sorl.thumbnail',
160161

161162
'users',
162163
'boxes',

pydotorg/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
# other section landing pages
4343
url(r'^psf-landing/$', TemplateView.as_view(template_name="psf/index.html"), name='psf-landing'),
44+
url(r'^psf/sponsors/$', TemplateView.as_view(template_name="psf/sponsors-list.html"), name='psf-sponsors'),
4445
url(r'^docs-landing/$', TemplateView.as_view(template_name="docs/index.html"), name='docs-landing'),
4546
url(r'^pypl-landing/$', TemplateView.as_view(template_name="pypl/index.html"), name='pypl-landing'),
4647
url(r'^shop-landing/$', TemplateView.as_view(template_name="shop/index.html"), name='shop-landing'),

sponsors/admin.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from ordered_model.admin import OrderedModelAdmin
22
from polymorphic.admin import PolymorphicInlineSupportMixin, StackedPolymorphicInline
33

4+
from django.template import Context, Template
45
from django.contrib import admin
56
from django.contrib.humanize.templatetags.humanize import intcomma
67
from django.urls import path
@@ -45,6 +46,7 @@ class LogoPlacementConfigurationInline(StackedPolymorphicInline.Child):
4546

4647
@admin.register(SponsorshipBenefit)
4748
class SponsorshipBenefitAdmin(PolymorphicInlineSupportMixin, OrderedModelAdmin):
49+
change_form_template = "sponsors/admin/sponsorshipbenefit_change_form.html"
4850
inlines = [BenefitFeatureConfigurationInline]
4951
ordering = ("program", "order")
5052
list_display = [
@@ -87,6 +89,20 @@ class SponsorshipBenefitAdmin(PolymorphicInlineSupportMixin, OrderedModelAdmin):
8789
),
8890
]
8991

92+
def get_urls(self):
93+
urls = super().get_urls()
94+
my_urls = [
95+
path(
96+
"<int:pk>/update-related-sponsorships",
97+
self.admin_site.admin_view(self.update_related_sponsorships),
98+
name="sponsors_sponsorshipbenefit_update_related",
99+
),
100+
]
101+
return my_urls + urls
102+
103+
def update_related_sponsorships(self, *args, **kwargs):
104+
return views_admin.update_related_sponsorships(self, *args, **kwargs)
105+
90106

91107
@admin.register(SponsorshipPackage)
92108
class SponsorshipPackageAdmin(OrderedModelAdmin):
@@ -103,6 +119,7 @@ class SponsorContactInline(admin.TabularInline):
103119
@admin.register(Sponsor)
104120
class SponsorAdmin(ContentManageableModelAdmin):
105121
inlines = [SponsorContactInline]
122+
search_fields = ["name"]
106123

107124

108125
class SponsorBenefitInline(admin.TabularInline):
@@ -152,6 +169,7 @@ class SponsorshipAdmin(admin.ModelAdmin):
152169
change_form_template = "sponsors/admin/sponsorship_change_form.html"
153170
form = SponsorshipReviewAdminForm
154171
inlines = [SponsorBenefitInline]
172+
search_fields = ["sponsor__name"]
155173
list_display = [
156174
"sponsor",
157175
"status",
@@ -306,7 +324,10 @@ def get_sponsor_landing_page_url(self, obj):
306324
get_sponsor_landing_page_url.short_description = "Landing Page URL"
307325

308326
def get_sponsor_web_logo(self, obj):
309-
html = f"<img src='{obj.sponsor.web_logo.url}'/>"
327+
html = "{% load thumbnail %}{% thumbnail sponsor.web_logo '150x150' format='PNG' quality=100 as im %}<img src='{{ im.url}}'/>{% endthumbnail %}"
328+
template = Template(html)
329+
context = Context({'sponsor': obj.sponsor})
330+
html = template.render(context)
310331
return mark_safe(html)
311332

312333
get_sponsor_web_logo.short_description = "Web Logo"
@@ -315,7 +336,10 @@ def get_sponsor_print_logo(self, obj):
315336
img = obj.sponsor.print_logo
316337
html = ""
317338
if img:
318-
html = f"<img src='{img.url}'/>"
339+
html = "{% load thumbnail %}{% thumbnail img '150x150' format='PNG' quality=100 as im %}<img src='{{ im.url}}'/>{% endthumbnail %}"
340+
template = Template(html)
341+
context = Context({'img': img})
342+
html = template.render(context)
319343
return mark_safe(html) if html else "---"
320344

321345
get_sponsor_print_logo.short_description = "Print Logo"

sponsors/forms.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from django import forms
33
from django.conf import settings
44
from django.contrib.admin.widgets import AdminDateWidget
5+
from django.db.models import Q
6+
from django.utils import timezone
57
from django.utils.functional import cached_property
68
from django.utils.text import slugify
79
from django.utils.translation import ugettext_lazy as _
@@ -394,3 +396,27 @@ def save(self, commit=True):
394396
self.instance.save()
395397

396398
return self.instance
399+
400+
401+
class SponsorshipsListForm(forms.Form):
402+
sponsorships = forms.ModelMultipleChoiceField(
403+
required=True,
404+
queryset=Sponsorship.objects.select_related("sponsor"),
405+
widget=forms.CheckboxSelectMultiple,
406+
)
407+
408+
@classmethod
409+
def with_benefit(cls, sponsorship_benefit, *args, **kwargs):
410+
"""
411+
Queryset considering only valid sponsorships which have the benefit
412+
"""
413+
today = timezone.now().date()
414+
queryset = sponsorship_benefit.related_sponsorships.exclude(
415+
Q(end_date__lt=today) | Q(status=Sponsorship.REJECTED)
416+
).select_related("sponsor")
417+
418+
form = cls(*args, **kwargs)
419+
form.fields["sponsorships"].queryset = queryset
420+
form.sponsorship_benefit = sponsorship_benefit
421+
422+
return form

sponsors/managers.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from ordered_model.models import OrderedModelManager
33
from django.db.models import Q, Subquery
44
from django.db.models.query import QuerySet
5+
from django.utils import timezone
6+
7+
from .enums import PublisherChoices
58

69

710
class SponsorshipQuerySet(QuerySet):
@@ -23,6 +26,22 @@ def visible_to(self, user):
2326
def finalized(self):
2427
return self.filter(status=self.model.FINALIZED)
2528

29+
def enabled(self):
30+
"""Sponsorship which are finalized and enabled"""
31+
today = timezone.now().date()
32+
qs = self.finalized()
33+
return qs.filter(start_date__lte=today, end_date__gte=today)
34+
35+
def with_logo_placement(self, logo_place=None, publisher=None):
36+
from sponsors.models import LogoPlacement, SponsorBenefit
37+
feature_qs = LogoPlacement.objects.all()
38+
if logo_place:
39+
feature_qs = feature_qs.filter(logo_place=logo_place)
40+
if publisher:
41+
feature_qs = feature_qs.filter(publisher=publisher)
42+
benefit_qs = SponsorBenefit.objects.filter(id__in=Subquery(feature_qs.values_list('sponsor_benefit_id', flat=True)))
43+
return self.filter(id__in=Subquery(benefit_qs.values_list('sponsorship_id', flat=True)))
44+
2645

2746
class SponsorContactQuerySet(QuerySet):
2847
def get_primary_contact(self, sponsor):

sponsors/models.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from django.core.files.storage import default_storage
77
from django.core.exceptions import ObjectDoesNotExist
88
from django.db import models, transaction
9-
from django.db.models import Sum
9+
from django.db.models import Sum, Subquery
1010
from django.template.defaultfilters import truncatechars
1111
from django.utils import timezone
1212
from django.utils.functional import cached_property
@@ -211,6 +211,11 @@ def remaining_capacity(self):
211211
def features_config(self):
212212
return self.benefitfeatureconfiguration_set
213213

214+
@property
215+
def related_sponsorships(self):
216+
ids_qs = self.sponsorbenefit_set.values_list("sponsorship__pk", flat=True)
217+
return Sponsorship.objects.filter(id__in=Subquery(ids_qs))
218+
214219
def __str__(self):
215220
return f"{self.program} > {self.name}"
216221

0 commit comments

Comments
 (0)