Skip to content

Commit 2d3fb8c

Browse files
committed
feat: initial work on short link management
1 parent c18327f commit 2d3fb8c

File tree

9 files changed

+99
-0
lines changed

9 files changed

+99
-0
lines changed

infographics/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
'web',
5656
'graphs',
5757
'video',
58+
'shortlink',
5859
]
5960

6061
MIDDLEWARE = [

shortlink/__init__.py

Whitespace-only changes.

shortlink/admin.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.contrib import admin
2+
3+
from shortlink.models import ShortLink
4+
5+
@admin.register(ShortLink)
6+
class ShortLinkAdmin(admin.ModelAdmin):
7+
list_display = ["id", "query"]

shortlink/apps.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class ShortlinkConfig(AppConfig):
5+
default_auto_field = 'django.db.models.BigAutoField'
6+
name = 'shortlink'
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Generated by Django 4.2.24 on 2025-10-22 14:30
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
initial = True
9+
10+
dependencies = [
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='ShortLink',
16+
fields=[
17+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18+
('query', models.TextField()),
19+
],
20+
),
21+
]

shortlink/migrations/__init__.py

Whitespace-only changes.

shortlink/models.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from django.db import models
2+
from sqids import Sqids
3+
4+
5+
class ShortLinkManager(models.Manager):
6+
def sqids(self):
7+
return Sqids()
8+
9+
def encode(self, id):
10+
return self.sqids().encode([id])
11+
12+
def decode(self, encoded):
13+
return self.sqids().decode(encoded)[0]
14+
15+
def encoded_id_from_query(self, query):
16+
short_link, created = self.get_or_create(query=query)
17+
return self.encode(short_link.id)
18+
19+
def query_from_encoded_id(self, encoded):
20+
id = self.decode(encoded)
21+
return self.get(id=id).query
22+
23+
24+
class ShortLink(models.Model):
25+
query = models.TextField()
26+
27+
objects = ShortLinkManager()

shortlink/tests.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from django.test import TestCase
2+
3+
from .models import ShortLink
4+
5+
6+
class ShortLinkTests(TestCase):
7+
QUERY = """
8+
#title: population of Brazilian non-capital municipalities
9+
SELECT ?item ?itemLabel ?stateLabel ?population ?date WHERE {
10+
?item wdt:P31 wd:Q3184121.
11+
?item p:P1082 ?population_node.
12+
?population_node ps:P1082 ?population.
13+
?population_node pq:P585 ?date.
14+
?population_node pq:P459 wd:Q39825. # only census
15+
MINUS { ?item wdt:P1376 []. } # remove capitals
16+
?item wdt:P131 ?state. # group by state
17+
FILTER (?date >= "1970-01-01"^^xsd:dateTime) # after 1970
18+
SERVICE wikibase:label { bd:serviceParam wikibase:language "pt-br". }
19+
}
20+
"""
21+
22+
def test_encode_and_decode(self):
23+
encoded = ShortLink.objects.encoded_id_from_query(self.QUERY)
24+
query = ShortLink.objects.query_from_encoded_id(encoded)
25+
self.assertEqual(query, self.QUERY)
26+
27+
def test_existant_query(self):
28+
sl = ShortLink.objects.create(query=self.QUERY)
29+
encoded = ShortLink.objects.encoded_id_from_query(self.QUERY)
30+
encoded2 = ShortLink.objects.encode(sl.id)
31+
self.assertEqual(
32+
ShortLink.objects.decode(encoded),
33+
ShortLink.objects.decode(encoded2),
34+
)

shortlink/views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.shortcuts import render
2+
3+
# Create your views here.

0 commit comments

Comments
 (0)