[Django] URL 단축 서비스 만들기

2026. 6. 10. 22:29·Django
반응형

 

Django 강의에서 URL 단축 서비스 실습을 진행했다.

URL 단축 서비스는 긴 웹 주소를 짧은 주소로 변환해 주는 서비스이다.

예를 들어 아래와 같은 긴 URL이 있다고 가정해보자.

http://www.climate-skeptic.com/2008/10/global-warming-accelerating.html

이 주소를 다음과 같이 짧게 줄일 수 있다.

https://bit.ly/x

사용자는 짧은 URL로 접속하지만, 실제로는 원래의 긴 URL로 이동하게 된다.

 


 

프로젝트 생성

먼저 URL 단축 서비스를 만들기 위한 Django 프로젝트를 생성한다.

  • 가상환경 생성
    • `python3.13 -m venv .short_url`
  • 가상환경 활성화
    • Mac: `source .short_url/bin/activate`
    • Windows: `source .short_url\Scripts\activate`
  • Django 설치
    • `pip install django`
  • 프로젝트 디렉토리 생성
    • `mkdir short_url`
  • Django 프로젝트 생성
    • `django-admin startproject config short_url`
  • 프로젝트로 이동
    • `cd short_url`
  • 서버 실행
    • `python manage.py runserver`

 


 

앱 생성

사용자 기능과 URL 단축 기능을 분리하기 위해 두 개의 앱을 생성했다.

  • `python manage.py startapp user`
  • `python manage.py startapp shortener`

생성한 앱은 `settings.py`의 `INSTALLED_APPS`에 등록한다.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user.apps.UserConfig',
    'shortener.apps.ShortenerConfig',
]

 


 

CustomUser 추가

Django 프로젝트에서는 기본 User 모델을 그대로 사용할 수도 있지만, 이후 확장 가능성을 고려해서 CustomUser를 정의했다.

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    pass

 

그리고 `settings.py`에 사용할 User 모델을 지정한다.

  • `AUTH_USER_MODEL = "user.CustomUser"`

User 모델을 변경했으면 마이그레이션을 적용해야 한다.

  • `python manage.py makemigrations`
  • `python manage.py migrate`

 


 

API 설계

URL 단축 서비스에서 사용할 기능은 다음과 같이 설계했다.

Method URL 설명
GET / 홈 화면, 모든 Short URL 목록
POST /short-urls/ 새로운 Short URL 생성
GET /<str:short_url>/ 원래 URL로 리디렉트
DELETE /<str:short_url>/ Short URL 삭제

예를 들어 `http://127.0.0.1:8000/b7ea4iQ/` 주소로 접속하면 `b7ea4iQ`에 해당하는 원래 주소로 이동한다.

 


 

ShortURL 모델

URL 단축 정보를 저장하기 위해 `ShortURL` 모델을 만들었다.

import string
import random

from django.db import models

class ShortURL(models.Model):
    code = models.CharField(max_length=8, unique=True)
    original_url = models.URLField(max_length=200)
    access_count = models.PositiveIntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

    # {app_label}_{클래스 이름 소문자}
    # db table: shortener_ shorturl -> short_url
    class Meta:
        app_label = "shortener"
        db_table = "short_url"
    
    @staticmethod
    def generate_code():
        characters = string.ascii_letters + string.digits
        return "".join(random.choices(characters, k=8))
  • `code` 필드에는 `unique=True` 적용
    • 데이터베이스에 Unique 제약 조건을 생성한다는 의미
    • 동일한 `code` 값을 가진 데이터가 중복 저장되지 않음

 


 

Form 사용의 한계

HTML Form 기반 요청에서는 기본적으로 `GET`과 `POST` 메서드만 사용할 수 있다.

즉, RESTful하게 설계한 아래 요청은 HTML Form만으로는 바로 보내기 어렵다.

  • `DELETE /<str:code>/`

그래서 브라우저에서 Form을 사용할 때는 삭제 요청을 어떻게 처리할지 고민이 필요하다.

 

해결 방법

1. RESTful한 API 디자인 포기하고 URL 변경

삭제 요청을 DELETE가 아니라 POST로 처리한다.

  • ` POST /<str:code>/delete/`

HTML Form에서 `POST` 요청을 보내고, Django View에서는 이를 삭제 요청으로 처리한다.

<form method="post" action="/abc123/delete/">
  {% csrf_token %}
  <button type="submit">삭제</button>
</form>

간단하게 사용할 수 있지만, RESTful하지 않아 아쉽다.

 

2. Form에서 POST로 요청하고, Django에서 DELETE로 처리

Django Middleware를 사용하는 방법이다.

 

Form은 POST로 보내되, hidden input을 추가해서 실제 의도를 표시한다.

<form method="post" action="/abc123/">
  {% csrf_token %}
  <input type="hidden" name="_method" value="DELETE">
  <button type="submit">삭제</button>
</form>

Django에서는 _method 값을 확인해서 삭제 로직을 실행한다.

Middleware를 사용하면 요청이 View에 도달하기 전에 공통 로직을 처리할 수 있다.

예를 들어 Form에서 `_method=DELETE` 값을 보내면 Middleware가 이를 확인하고 요청 메서드를 DELETE로 바꿀 수 있다.

 


 

Django MiddleWare

Middleware는 요청과 응답 사이에서 실행되는 중간 처리 계층이다.

사용자의 요청은 View에 도달하기 전에 Middleware를 거친다.

Request → Middleware → View → Middleware → Response

따라서 로그인 확인, 보안 처리, 공통 예외 처리, 요청 데이터 가공 같은 작업을 Middleware에서 처리할 수 있다.

이번 프로젝트에서는 Form에서 보낸 _method 값을 확인해 요청 메서드를 바꾸는 용도로 활용할 수 있다.

 


 

ShortURL 삭제 처리

HTML Form은 DELETE 요청을 직접 보낼 수 없기 때문에 hidden input을 사용했다.

<form action="{% url 'short_url_detail' short_url.code %}" method="post">
    {% csrf_token %}
    <input type="hidden" name="_method" value="DELETE">
    <button type="submit" class="btn btn-danger">삭제</button>
</form>

View에서는 다음과 같이 처리할 수 있다.

class ShortURLDetailView(View):
    # localhost:8000/abc12345 -> original_url
    def get(self, request, code):
        short_url = get_object_or_404(ShortURL, code=code)    
        short_url.access_count = F("access_count") + 1
        short_url.save()  
        return redirect(short_url.original_url)

    def delete(self, request, code):
        short_url = get_object_or_404(ShortURL, code=code)
        short_url.delete()
        return redirect("home")

이렇게 하면 실제 HTTP 요청은 POST이지만, 서버에서는 삭제 요청으로 해석할 수 있다.

 

 

[참고] 실전! Django 입문 강의

반응형
'Django' 카테고리의 다른 글
  • [Django] Kakao 소셜 로그인
  • [Django] 장고 회원 시스템 (Session과 User Model)
  • [Django] 장고 회원 시스템 (User 모델과 Admin 페이지)
  • [Django] Function-Based View와 Class-Based View
올콩
올콩
콩 심은 데 콩 난다
  • 올콩
    콩스토리
    올콩
  • 전체
    오늘
    어제
    • 분류 전체보기 (226) N
      • SSAFY (10)
      • Algorithm (123)
        • 이론 (6)
        • 백준 (BOJ) (114)
        • 프로그래머스 (2)
        • 코드트리 (1)
      • Trouble Shooting (11)
      • Frontend (7)
      • React (17)
      • Next.js (5)
      • Vue (4)
      • Django (12) N
      • Node.js (2)
      • HTML (9)
      • DevOps (4)
        • Git (4)
      • Language (13)
        • JavaScript (0)
        • Java (13)
      • Embedded (1)
      • CS (5)
        • Network (1)
        • Blockchain (4)
      • 자격증 (2)
      • 기타 (1)
        • Tistory (1)
  • 블로그 메뉴

    • GitHub
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    SSAFYcial
    bfs
    dfs
    django
    Java
    수학
    우선순위큐
    티스토리챌린지
    SSAFY
    Heap
    알고리즘
    힙
    구현
    싸피
    브루트포스
    그리디
    백준
    파이썬
    Algorithm
    강의
    React
    블록체인
    DP
    오블완
    순열
    html5
    백트래킹
    Error
    중복순열
    Next.js
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
올콩
[Django] URL 단축 서비스 만들기
상단으로

티스토리툴바