Skip to content

Commit aea0809

Browse files
authored
Merge pull request #195 from sandiegopython/davidfischer/sponsors-db-driven
Make sponsors DB driven
2 parents 6a82601 + 42dd551 commit aea0809

File tree

12 files changed

+206
-19
lines changed

12 files changed

+206
-19
lines changed

pythonsd/admin.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
11
from django.contrib import admin
2+
from django.utils.html import format_html
23

34
from .models import Organizer
5+
from .models import Sponsor
46

57

68
admin.site.register(Organizer)
9+
10+
11+
@admin.register(Sponsor)
12+
class SponsorAdmin(admin.ModelAdmin):
13+
# This is the width used in the admin interface
14+
MAX_IMAGE_WIDTH = 100
15+
16+
list_display = (
17+
"display_logo",
18+
"name",
19+
"active",
20+
"order",
21+
)
22+
list_filter = ("active",)
23+
readonly_fields = ("display_logo",)
24+
ordering = ("order",)
25+
26+
@admin.display(description="Logo")
27+
def display_logo(self, obj):
28+
"""Display the sponsor logo in the admin interface."""
29+
if not obj:
30+
return ""
31+
32+
return format_html(
33+
'<img src="{}" style="max-width: {}px" />',
34+
obj.logo.url,
35+
self.MAX_IMAGE_WIDTH,
36+
)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Generated by Django 5.2.8 on 2025-11-23 17:00
2+
3+
from django.db import migrations
4+
from django.db import models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("pythonsd", "0001_initial"),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name="Sponsor",
15+
fields=[
16+
(
17+
"id",
18+
models.BigAutoField(
19+
auto_created=True,
20+
primary_key=True,
21+
serialize=False,
22+
verbose_name="ID",
23+
),
24+
),
25+
("name", models.CharField(max_length=255)),
26+
(
27+
"website_url",
28+
models.URLField(blank=True, default="", max_length=1024),
29+
),
30+
("description", models.TextField(blank=True, default="")),
31+
(
32+
"logo",
33+
models.ImageField(
34+
help_text="Recommended size of 300*300px or larger square",
35+
upload_to="sponsors/",
36+
),
37+
),
38+
(
39+
"active",
40+
models.BooleanField(
41+
default=True,
42+
help_text="Set to False to hide this sponsor from the sponsors page",
43+
),
44+
),
45+
(
46+
"order",
47+
models.PositiveSmallIntegerField(
48+
default=0,
49+
help_text="Sponsors are displayed in ascending order of this value",
50+
),
51+
),
52+
],
53+
options={
54+
"ordering": ("order",),
55+
},
56+
),
57+
]

pythonsd/models.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,33 @@ class Organizer(models.Model):
2020

2121
def __str__(self):
2222
return self.name
23+
24+
25+
class Sponsor(models.Model):
26+
"""Meetup sponsors - displayed on the home page page."""
27+
28+
name = models.CharField(max_length=255)
29+
website_url = models.URLField(
30+
max_length=1024,
31+
blank=True,
32+
default="",
33+
)
34+
description = models.TextField(blank=True, default="")
35+
logo = models.ImageField(
36+
upload_to="sponsors/",
37+
help_text="Recommended size of 300*300px or larger square",
38+
)
39+
active = models.BooleanField(
40+
default=True,
41+
help_text="Set to False to hide this sponsor from the sponsors page",
42+
)
43+
order = models.PositiveSmallIntegerField(
44+
default=0,
45+
help_text="Sponsors are displayed in ascending order of this value",
46+
)
47+
48+
def __str__(self):
49+
return self.name
50+
51+
class Meta:
52+
ordering = ("order",)
-2.5 KB
Binary file not shown.
-14.4 KB
Binary file not shown.
-1.29 KB
Binary file not shown.
-7.21 KB
Binary file not shown.
-3.04 KB
Binary file not shown.

pythonsd/templates/pythonsd/index.html

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,23 +68,25 @@ <h2>Upcoming meetups</h2>
6868
<h2>Sponsors</h2>
6969
<p>These fine companies help to make San Diego Python a success.</p>
7070

71-
<figure class="flex items-center space-x-4">
72-
<img src="{% static 'img/sponsors/qualcomm-logo.png' %}" class="flex-none h-16" alt="Qualcomm">
73-
<figcaption class="flex-auto">
74-
<h5 class="mt-0 mb-1"><a href="https://www.qualcomm.com/" rel="nofollow noopener noreferrer">Qualcomm</a></h5>
75-
<p class="m-0">Qualcomm provides the venue for our monthly meetup.</p>
76-
</figcaption>
77-
</figure>
78-
79-
<figure class="flex items-center space-x-4">
80-
<img src="{% static 'img/sponsors/neo4j-logo.png' %}" class="flex-none h-16" alt="Neo4j">
81-
<figcaption class="flex-auto">
82-
<h5 class="mt-0 mb-1"><a href="https://neo4j.com/" rel="nofollow noopener noreferrer">Neo4j</a></h5>
83-
<p class="m-0">Neo4j is providing food at our monthly meetup.</p>
84-
</figcaption>
85-
</figure>
86-
87-
<p class="text-sm">You can <a href="https://psfmember.org/civicrm/contribute/transact/?reset=1&id=9">donate to San Diego Python</a> through the PSF. Your donation may be tax deductible. All donations go toward events, workshops, and training materials.</p>
71+
{% if sponsors %}
72+
{% for sponsor in sponsors %}
73+
<figure class="flex items-center space-x-4 mb-4">
74+
<img src="{{ sponsor.logo.url }}" class="flex-none h-16" alt="{{ sponsor.name }}">
75+
<figcaption class="flex-auto">
76+
<h5 class="mt-0 mb-1"><a href="{{ sponsor.website_url }}" rel="nofollow noopener noreferrer">{{ sponsor.name }}</a></h5>
77+
<p class="m-0">{{ sponsor.description }}</p>
78+
</figcaption>
79+
</figure>
80+
{% endfor %}
81+
{% else %}
82+
<!-- No sponsors at this time. -->
83+
{% endif %}
84+
85+
<p class="text-sm">
86+
<span>You can <a href="https://psfmember.org/civicrm/contribute/transact/?reset=1&id=9">donate to San Diego Python</a> through the PSF.</span>
87+
<span>Your donation may be tax deductible. All donations go toward events, workshops, and training materials.</span>
88+
<span>Interested in sponsoring the meetup? Get in touch with the <a href="{% url 'organizers' %}">organizers</a>.</span>
89+
</p>
8890

8991
</div>
9092

pythonsd/tests/__init__.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from config import wsgi
1919

2020
from ..models import Organizer
21+
from ..models import Sponsor
2122
from ..views import RecentVideosView
2223
from ..views import UpcomingEventsView
2324

@@ -49,12 +50,44 @@ def test_coc_redirect(self):
4950

5051

5152
class TestHomepageView(test.TestCase):
52-
def test_homepage(self):
53-
response = self.client.get(reverse("index"))
53+
def setUp(self):
54+
self.url = reverse("index")
55+
56+
def test_homepage_nosponsor(self):
57+
response = self.client.get(self.url)
5458
self.assertContains(
5559
response,
5660
"San Diego Python is a Python programming language special interest group",
5761
)
62+
self.assertContains(
63+
response,
64+
"No sponsors at this time",
65+
)
66+
67+
def test_homepage_withsponsor(self):
68+
sponsor = Sponsor(
69+
name="First Sponsor",
70+
website_url="http://example.com/",
71+
description="A great sponsor",
72+
logo=SimpleUploadedFile(
73+
name="test.png", content=ONE_PIXEL_PNG_BYTES, content_type="image/png"
74+
),
75+
)
76+
sponsor.save()
77+
78+
response = self.client.get(self.url)
79+
self.assertContains(
80+
response,
81+
sponsor.name,
82+
)
83+
self.assertContains(
84+
response,
85+
sponsor.description,
86+
)
87+
self.assertNotContains(
88+
response,
89+
"No sponsors at this time",
90+
)
5891

5992

6093
class TestOrganizersView(test.TestCase):

0 commit comments

Comments
 (0)