├── README.md └── URLShortnerProject ├── URLShortnerApp ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── admin.cpython-37.pyc │ ├── forms.cpython-37.pyc │ ├── models.cpython-37.pyc │ ├── serializers.cpython-37.pyc │ ├── urls.cpython-37.pyc │ └── views.cpython-37.pyc ├── admin.py ├── apps.py ├── forms.py ├── models.py ├── serializers.py ├── static │ └── images.text ├── templates │ └── myform │ │ └── form.html ├── tests.py ├── urls.py └── views.py ├── URLShortnerProject ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── manage.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # Custom Django URL Shortener App 2 | Instructions on how to build project within one hour can be viewed at: https://www.youtube.com/watch?v=ctuSR6UHcuQ 3 |
Instruction on how to deploy: https://youtu.be/hYMTvK5MpQI 4 | 5 | ## Building Your First Custom App in 1 Hour 6 | 7 | This project is a great beginner friendly project. In this tutorial we walk through how to build a URL shortening service. You can check out the youtube tutorial above on a code walk through. We use django as the backend, html with bootstrap as the front end and ORM with SQLite3 for data management. All files relevant to build the application are included in this respository 8 | 9 | ## Deploy to a Cloud Server 10 | 11 | ### Set Up Server 12 | 13 | You can use something like Linode or Digital Ocean to follow these instruction. 14 | 15 | Step 1: Create a linode or droplet (I use the $5 tier for this project) 16 | 17 | Step 2: Use terminal or any ssh client to login with root and run:
18 | ```ssh root@IP```
```apt update && apt upgrade -y``` 19 | 20 | Step 3: Set hostname for server. I used test-server. You can use whatever you want. 21 |
```hostnamectl set-hostname test-server``` 22 | 23 | Step 4: Connect host ip and hostname 24 |
run ```nano /etc/hosts``` and add your server ip, click tab and then your hostname (from step 3) 25 | 26 | Step 5: Install some dependencies 27 |
run ```sudo apt install python-pip virtualenv ufw``` 28 | 29 | Step 6: Create a limited user and give sudo privlidges
30 | 31 | run ```adduser USERNAME``` <---pick anything here. Enter password and skip through the rest of the questions.
32 | then run ```adduser USERNAME sudo```
33 | logout as root by typing ```exit``` and log in with your username: ```ssh username@IP``` 34 | 35 | Step 7: Set up some firewall rules and enable
36 | 37 | ```sudo ufw default allow outgoing```
38 | ```sudo ufw default deny incoming```
39 | ```sudo ufw allow ssh```
40 | ```sudo ufw allow 8000```
41 | ```sudo ufw enable```
42 | ```sudo ufw status``` (check to ensure its up and running)

43 | 44 | Step 8: Setup ssh keys on your local computer
45 | run ```ssh-keygen -b 4096```
leave defaults
46 | run ```ssh-copy-id username@IP``` to push them to your server
47 | optional: If you have multiple ssh key pairs then run ```ssh-add ~/.ssh/{name of ssh key}``` 48 | 49 | Step 9:Remove root login and password auth
50 | run ```sudo nano /etc/ssh/sshd_config```
51 | Set permit root login to no and uncomment passwordauthentication and set it to no
52 | 53 | Step 10: Reboot the server
54 | run ```sudo reboot``` 55 | 56 | ### Deploy Django Project to Server 57 | 58 | Step 11: Change to your virtualenv
59 | run ```virtualenv vevn -p python3```
60 | run ```source venv/bin/activate```
61 | You should now see something like (venv) on your terminal line 62 | 63 | Step 12: Transfer Django project from local computer to server
64 | run ```scp -r {local path to project folder} username@IP:~/``` 65 | 66 | Step 13: Update settings.py. Navigate to settings.py in your project folder
67 | Set ```Debug=False```
68 | Update ```Allowed_Hosts =['Add Your IP or Domain Name']```
69 | Add static root with the following command ```STATIC_ROOT = os.path.join(BASE_DIR, ‘static')``` to the settings file
70 | Save and exit 71 | 72 | Step 14: Back out to the directory that has manage.py
73 | Run ```python manage.py collectstatic``` 74 | 75 | Step 15: Install Gunicorn and Nginx
76 | run ```pip install gunicorn```
77 | run ```sudo apt install nginx libpq-dev``` 78 | 79 | Step 16: Check to see if gunicorn can host your django project. Change URLShortnerProject to whatever your project is called
80 | run ```gunicorn --bind 0.0.0.0:8000 URLShortnerProject.wsgi``` 81 | 82 | Step 17: Deactivate venv and Create gunicorn systemd file
83 | run ```deactivate```. The (venv) on terminal line should be gone
84 | run ```sudo nano /etc/systemd/system/gunicorn.service```
85 | Paste the following and be sure to update your project name, path and username accordingly:
86 | ``` 87 | [Unit] 88 | Description=gunicorn daemon 89 | After=network.target 90 | 91 | [Service] 92 | User=username 93 | Group=www-data 94 | WorkingDirectory=/home/username/URLShortnerProject 95 | ExecStart=/home/username/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/username/URLShortnerProject/URLShortnerProject.sock URLShortnerProject.wsgi:application 96 | 97 | [Install] 98 | WantedBy=multi-user.target 99 | ``` 100 | 101 | Step 18: Run the following commands to enable gunicorn:
102 | 103 | ```sudo systemctl start gunicorn```
104 | ```sudo systemctl enable gunicorn```
105 | ```sudo systemctl status gunicorn```
106 | ```sudo systemctl daemon-reload```
107 | ```sudo systemctl restart gunicorn```
108 |
109 | 110 | Step 19: Set up NGINX with GUNICORN
111 | run ```sudo nano /etc/nginx/sites-available/URLShortnerProject```
112 | Paste the following and be sure update your own IP, username, path and project name
113 | This covers http, https will be covered in a later tutorial
114 | 115 | ``` 116 | server { 117 | listen 80; 118 | server_name IP; 119 | location = /favicon.ico { access_log off; log_not_found off; } 120 | location /static/ { 121 | root /home/username/URLShortnerProject; 122 | } 123 | location / { 124 | include proxy_params; 125 | proxy_pass http://unix:/home/username/URLShortnerProject/URLShortnerProject.sock; 126 | } 127 | } 128 | ``` 129 | 130 | Step 20: Link and test nginx config 131 | 132 |
Link: ```sudo ln -s /etc/nginx/sites-available/URLShortnerProject /etc/nginx/sites-enabled``` 133 |
Test: ```sudo nginx -t``` 134 | 135 | Step 21: Change UFW Rules
136 | ```sudo ufw delete allow 8000```
137 | ```sudo ufw allow 'Nginx Full' ```
138 | 139 | Step 22: Reload Nginx and Gunicorn
140 | ```sudo systemctl restart gunicorn```
141 | ```sudo systemctl restart nginx```
142 | 143 | Now visit your ip and check out your django website on a cloud server 144 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satssehgal/URLShortnerDjango-/b57a62606ebb29ed071f4fd4542f26e4c8004a9e/URLShortnerProject/URLShortnerApp/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__pycache__/admin.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satssehgal/URLShortnerDjango-/b57a62606ebb29ed071f4fd4542f26e4c8004a9e/URLShortnerProject/URLShortnerApp/__pycache__/admin.cpython-37.pyc -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__pycache__/forms.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satssehgal/URLShortnerDjango-/b57a62606ebb29ed071f4fd4542f26e4c8004a9e/URLShortnerProject/URLShortnerApp/__pycache__/forms.cpython-37.pyc -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__pycache__/models.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satssehgal/URLShortnerDjango-/b57a62606ebb29ed071f4fd4542f26e4c8004a9e/URLShortnerProject/URLShortnerApp/__pycache__/models.cpython-37.pyc -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__pycache__/serializers.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satssehgal/URLShortnerDjango-/b57a62606ebb29ed071f4fd4542f26e4c8004a9e/URLShortnerProject/URLShortnerApp/__pycache__/serializers.cpython-37.pyc -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__pycache__/urls.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satssehgal/URLShortnerDjango-/b57a62606ebb29ed071f4fd4542f26e4c8004a9e/URLShortnerProject/URLShortnerApp/__pycache__/urls.cpython-37.pyc -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/__pycache__/views.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satssehgal/URLShortnerDjango-/b57a62606ebb29ed071f4fd4542f26e4c8004a9e/URLShortnerProject/URLShortnerApp/__pycache__/views.cpython-37.pyc -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from URLShortnerApp.models import URLData 3 | 4 | admin.site.register(URLData) -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class UrlshortnerappConfig(AppConfig): 5 | name = 'URLShortnerApp' 6 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | class URLDataForm(forms.Form): 4 | EnterURL=forms.CharField(label='Enter Your URL ', max_length=1000, widget=forms.TextInput(attrs={'placeholder': 'Shorten URL Here'})) 5 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class URLData(models.Model): 4 | URLID=models.CharField(max_length=1000) 5 | ShortURL=models.CharField(max_length=1000) 6 | 7 | def __str__(self): 8 | template = '{0.URLID}, {0.ShortURL}' 9 | return template.format(self) 10 | 11 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from . models import URLData 3 | 4 | class URLDataSerializers(serializers.ModelSerializer): 5 | class Meta: 6 | model=URLData 7 | fields='__all__' 8 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/static/images.text: -------------------------------------------------------------------------------- 1 | Feel Free to use your own images. If you are putting this into production then you cannot use static fields 2 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/templates/myform/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | URL Shortner 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 | 18 | 19 | 20 | 22 | 23 |
Sign UpLogin 21 |
24 | 25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
HOMESERVICESPRICINGABOUTFAQ
46 |
47 |
48 |
49 |
50 | 51 |
52 | 53 | 54 |
55 | 56 | 57 |
58 |
59 | {% load static %} 60 | Python 61 |
62 | 63 | 64 | 65 |
66 |

Short N' Sweet

67 |

68 |
69 | 70 |
71 |
72 |
73 | 74 |
75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 |
83 | 84 | 85 | {% block content %} 86 |

87 |
88 | {% csrf_token %} 89 | {{ form.EnterURL }} 90 | 91 |

92 | {% endblock %} 93 | 94 | {% if messages %} 95 |
    96 | {% for message in messages %} 97 |

    98 |
    {{message }}
    99 | {% endfor %} 100 |
101 | {% endif %} 102 |
103 |
104 |
105 | 106 | 107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |

Made with:

116 | 117 |
118 |
119 |
120 |
121 | 122 | 123 |
124 | {% load static %} 125 | Django 126 |
127 |
128 | {% load static %} 129 | Python 130 |
131 |
132 | {% load static %} 133 | Bootstrap 134 |
135 |
136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from django.conf.urls.static import static 3 | from django.views.generic import RedirectView 4 | from . import views 5 | 6 | urlpatterns = [ 7 | path('', RedirectView.as_view(url='/shorten/')), 8 | path('shorten/', views.get_form, name='urlform'), 9 | path('/', views.redirect_short_url, name='redirectpath'), 10 | ] 11 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerApp/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from rest_framework import viewsets, status 3 | from rest_framework.decorators import api_view 4 | from django.core import serializers 5 | from django.contrib import messages 6 | from rest_framework.response import Response 7 | from django.http import JsonResponse 8 | from rest_framework.parsers import JSONParser 9 | from django.db import connection 10 | from . models import URLData 11 | from . forms import URLDataForm 12 | from . serializers import URLDataSerializers 13 | from django.shortcuts import redirect 14 | import sqlite3 15 | import string 16 | import random 17 | 18 | #Declare Key Varaibles 19 | BASE_LIST='0123456789abcdefghijklmnopqrstuvwxyz./:' 20 | BASE_DICT=dict((c,idx) for idx,c in enumerate(BASE_LIST)) 21 | service_url='127.0.0.1' 22 | 23 | class FullURLView(viewsets.ModelViewSet): 24 | queryset=URLData.objects.all() 25 | serializers_class=URLDataSerializers 26 | 27 | def base_encode(integer, alphabet=BASE_LIST): #Convert ID to FullURL 28 | if integer == 0: 29 | return alphabet[0] 30 | arr = [] 31 | base = len(alphabet) 32 | while integer: 33 | integer, rem = divmod(integer, base) 34 | arr.append(alphabet[rem]) 35 | arr.reverse() 36 | return ''.join(arr) 37 | 38 | def base_decode(request, reverse_base=BASE_DICT): #Convert Full URL to ID 39 | longurl=request 40 | length = len(reverse_base) 41 | ret = 0 42 | for i, c in enumerate(longurl[::-1]): 43 | ret += (length ** i) * reverse_base[c] 44 | return ret 45 | 46 | def shortChars(): #Get Shortened URL endpoint 47 | SHORT_LIST_CHAR='0123456789'+string.ascii_letters 48 | return ''.join([random.choice(SHORT_LIST_CHAR) for i in range(10)]) 49 | 50 | def checkIDExists(ID): #Check to see if ID exists in DB 51 | sc=str(shortChars()) 52 | Retreived_IDs=list(URLData.objects.values_list('URLID', flat=True)) 53 | if str(ID) in Retreived_IDs: 54 | surl=URL_ID=URLData.objects.all().filter(URLID=str(ID))[0].ShortURL 55 | mess=("Record Already Exists. The Shortened Link is: {}/{}".format(service_url,surl)) 56 | else: 57 | U=URLData(URLID=ID, ShortURL=sc) 58 | U.save() 59 | mess=("Congratulatons! Your shortened URL is {}/{}".format(service_url,sc)) 60 | return mess 61 | 62 | def redirect_short_url(request, short_url): 63 | redirect_url = service_url+'/shorten' 64 | try: 65 | URL_ID=URLData.objects.all().filter(ShortURL=short_url)[0].URLID 66 | redirect_url = base_encode(int(URL_ID)) 67 | except Exception as e: 68 | print (e) 69 | return redirect(redirect_url) 70 | 71 | def appendPrefix(entry): 72 | match=['http','https'] 73 | if any(x in entry for x in match): 74 | return entry 75 | else: 76 | return('https://'+str(entry)) 77 | 78 | def get_form(request): 79 | if request.method=='POST': 80 | form=URLDataForm(request.POST) 81 | if form.is_valid(): 82 | fullurl=form.cleaned_data['EnterURL'] 83 | fullurladj=appendPrefix(fullurl) 84 | ID=base_decode(fullurladj.lower()) 85 | messages.success(request, '{}'.format(checkIDExists(ID))) 86 | form=URLDataForm() 87 | return render(request, 'myform/form.html', {'form':form}) 88 | 89 | 90 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerProject/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerProject/asgi.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | from django.core.asgi import get_asgi_application 5 | 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'URLShortnerProject.settings') 7 | 8 | application = get_asgi_application() 9 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerProject/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for URLShortnerProject project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.0.4. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '^twxc=fd0fzd_yz@qy-ogh8uxar20l)ed7lor@-p9g*p6o7t3d' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 31 | MEDIA_URL = '/media/' 32 | 33 | # Application definition 34 | 35 | INSTALLED_APPS = [ 36 | 'django.contrib.admin', 37 | 'django.contrib.auth', 38 | 'django.contrib.contenttypes', 39 | 'django.contrib.sessions', 40 | 'django.contrib.messages', 41 | 'django.contrib.staticfiles', 42 | 'URLShortnerApp', 43 | 'bootstrap4', 44 | 'crispy_forms', 45 | ] 46 | 47 | CRISPY_TEMPLATE_PACK = 'bootstrap4' 48 | 49 | MIDDLEWARE = [ 50 | 'django.middleware.security.SecurityMiddleware', 51 | 'django.contrib.sessions.middleware.SessionMiddleware', 52 | 'django.middleware.common.CommonMiddleware', 53 | 'django.middleware.csrf.CsrfViewMiddleware', 54 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 55 | 'django.contrib.messages.middleware.MessageMiddleware', 56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 57 | ] 58 | 59 | ROOT_URLCONF = 'URLShortnerProject.urls' 60 | 61 | TEMPLATES = [ 62 | { 63 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 64 | 'DIRS': [], 65 | 'APP_DIRS': True, 66 | 'OPTIONS': { 67 | 'context_processors': [ 68 | 'django.template.context_processors.debug', 69 | 'django.template.context_processors.request', 70 | 'django.contrib.auth.context_processors.auth', 71 | 'django.contrib.messages.context_processors.messages', 72 | ], 73 | }, 74 | }, 75 | ] 76 | 77 | WSGI_APPLICATION = 'URLShortnerProject.wsgi.application' 78 | 79 | 80 | # Database 81 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases 82 | 83 | DATABASES = { 84 | 'default': { 85 | 'ENGINE': 'django.db.backends.sqlite3', 86 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 87 | } 88 | } 89 | 90 | 91 | # Password validation 92 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators 93 | 94 | AUTH_PASSWORD_VALIDATORS = [ 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 106 | }, 107 | ] 108 | 109 | 110 | # Internationalization 111 | # https://docs.djangoproject.com/en/3.0/topics/i18n/ 112 | 113 | LANGUAGE_CODE = 'en-us' 114 | 115 | TIME_ZONE = 'UTC' 116 | 117 | USE_I18N = True 118 | 119 | USE_L10N = True 120 | 121 | USE_TZ = True 122 | 123 | 124 | # Static files (CSS, JavaScript, Images) 125 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ 126 | 127 | STATIC_URL = '/static/' 128 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerProject/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | from URLShortnerApp import views 4 | from . import settings 5 | 6 | urlpatterns = [ 7 | path('admin/', admin.site.urls), 8 | path('', include('URLShortnerApp.urls')), 9 | ] 10 | 11 | -------------------------------------------------------------------------------- /URLShortnerProject/URLShortnerProject/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for URLShortnerProject project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'URLShortnerProject.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /URLShortnerProject/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'URLShortnerProject.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /URLShortnerProject/requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.2.5 2 | beautifulsoup4==4.8.2 3 | certifi==2019.11.28 4 | chardet==3.0.4 5 | Django==3.0.4 6 | django-bootstrap4==1.1.1 7 | django-crispy-forms==1.9.0 8 | djangorestframework==3.11.0 9 | idna==2.9 10 | pytz==2019.3 11 | requests==2.23.0 12 | soupsieve==2.0 13 | sqlparse==0.3.1 14 | urllib3==1.25.8 15 | --------------------------------------------------------------------------------