如何基于Django利用URL id实现Base62编码的URL短链接服务
修复并完善短链接服务代码
1. 先修复URLGenerator的已知Bug
你的URLGenerator类缺少math模块导入,且_true_chr方法最后抛出异常时直接使用BASE未绑定实例,先修正这两处问题:
import math class URLGenerator: BASE = 62 UPPERCASE_OFFSET = 55 LOWERCASE_OFFSET = 61 DIGIT_OFFSET = 48 def generate_unique_key(self, integer): """ Turn an integer [integer] into a base [BASE] number in string representation """ if integer == 0: return '0' string = "" remainder: int = 0 while integer > 0: remainder = integer % self.BASE string = self._true_chr(remainder) + string integer = int(integer / self.BASE) return string def get_id(self, key): """ Turn the base [BASE] number [key] into an integer """ int_sum = 0 reversed_key = key[::-1] for idx, char in enumerate(reversed_key): int_sum += self._true_ord(char) * int(math.pow(self.BASE, idx)) return int_sum def _true_ord(self, char): """ Turns a digit [char] in character representation from the number system with base [BASE] into an integer. """ if char.isdigit(): return ord(char) - self.DIGIT_OFFSET elif 'A' <= char <= 'Z': return ord(char) - self.UPPERCASE_OFFSET elif 'a' <= char <= 'z': return ord(char) - self.LOWERCASE_OFFSET else: raise ValueError("%s is not a valid character" % char) def _true_chr(self, integer): """ Turns an integer [integer] into digit in base [BASE] as a character representation. """ if integer < 10: return chr(integer + self.DIGIT_OFFSET) elif 10 <= integer <= 35: return chr(integer + self.UPPERCASE_OFFSET) elif 36 <= integer < 62: return chr(integer + self.LOWERCASE_OFFSET) else: raise ValueError( "%d is not a valid integer in the range of base %d" % (integer, self.BASE))
2. 完善Url模型
你原来的Url模型缺少原始长链接字段,且save方法需要补充短码生成逻辑:
from django.db import models class Url(models.Model): url_id = models.AutoField(primary_key=True) original_url = models.URLField(verbose_name="原始长链接", max_length=500) short_code = models.CharField(verbose_name="短链编码", max_length=10, unique=True, blank=True) def save(self, *args, **kwargs): # 首次保存先调用父类方法生成自增ID if not self.pk: super().save(*args, **kwargs) # 基于自增ID生成短码 generator = URLGenerator() self.short_code = generator.generate_unique_key(self.url_id) # 移除强制插入参数,避免二次保存报错 kwargs.pop('force_insert', None) super().save(*args, **kwargs)
可选优化:如果需要避免同一个长链接重复生成短链,可以在创建数据前先查询
original_url是否已存在,存在则直接返回已有短链。
3. 编写views.py业务逻辑
提供两个核心接口:POST提交长链接生成短链、GET访问短码跳转到原始链接
from django.shortcuts import get_object_or_404, redirect from django.http import JsonResponse from django.views.decorators.http import require_http_methods from .models import Url # 生成短链的POST接口 @require_http_methods(["POST"]) def generate_short_url(request): original_url = request.POST.get("original_url") if not original_url: return JsonResponse({"code": 400, "msg": "缺少原始链接参数"}, status=400) # 存入数据库自动生成短码 url_obj = Url.objects.create(original_url=original_url) # 拼接完整短链返回 short_url = f"{request.scheme}://{request.get_host()}/{url_obj.short_code}" return JsonResponse({"code": 200, "short_url": short_url, "original_url": original_url}) # 短链跳转接口 @require_http_methods(["GET"]) def redirect_to_original(request, short_code): url_obj = get_object_or_404(Url, short_code=short_code) # 302临时跳转,需要统计点击量可在此处新增计数逻辑 return redirect(url_obj.original_url)
如果不想存储
short_code字段,可以注释掉模型中的对应字段,跳转时先通过URLGenerator().get_id(short_code)解码拿到url_id再查询即可。
4. 配置urls.py路由
在项目/应用的路由文件中添加对应规则:
from django.urls import path from . import views urlpatterns = [ path("generate/", views.generate_short_url, name="generate_short"), path("<str:short_code>/", views.redirect_to_original, name="redirect_original"), ]
效果验证
可以用curl工具发送测试请求:
curl -X POST -d "original_url=https://www.baidu.com" http://127.0.0.1:8000/generate/
请求成功会返回生成好的短链,直接访问短链即可跳转到对应原始链接。
内容的提问来源于stack exchange,提问作者Aylin Naebzadeh
相关产品推荐
相关产品推荐

