Important
- In this project
mainbranch isdevelopmentbranch - Use
deploybranch for deployment
-
We need to setup our project for deployment
-
requirements.txtmust be present, which contains all the required packages we use in our project -
For this project my project requirement package are listed in
requirements.txtDjango==6.0.5 gunicorn==26.0.0 pillow==12.2.0 whitenoise==6.12.0 django-cleanup==9.0.0 crispy-bootstrap5==2026.3
- We can generate this by running
pip freeze > requirements.txtor list these packages manually each time we install
- We can generate this by running
-
-
In
settings.pyfile modify as belowDEBUG = False ALLOWED_HOSTS = ["*"] # change this to domain website MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # This must be added here after SecurityMiddleware & SessionMiddleware ... ] # static STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'staticfiles/' STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # media MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR / 'media/'
-
Modify project
urls.py; this is for mediafrom django.contrib import admin from django.conf import settings from django.conf.urls.static import static from django.views.static import serve from django.urls import path, include, re_path urlpatterns = [ path('admin/', admin.site.urls), path('',include('imageApp.urls')), # for media re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}) ]
-
Now we have to run
collectstaticcommandpy manage.py collectstatic
- We will use this
collectstaticcommand in server, or we could just run it and zip the whole project and upload to the server (it's mainly depended on how static contents are being setup)` - As some free server does not allow running command so in
deploybranchstaticfilesare generated
- We will use this
-
For this we can use python-dotenv or python-decouple
-
-
Install it
pip install python-dotenv -
Create a
.envSECRET_KEY='write the key here' DEBUG=False
-
Now in settings.py
import os from dotenv import load_dotenv load_dotenv() SECRET_KEY = os.getenv('SECRET_KEY') DEBUG = os.getenv('DEBUG')
-
-
-
Install it
pip install python-decouple -
Create a
.envSECRET_KEY='write the key here' DEBUG=False
-
Now in settings.py
from decouple import config SECRET_KEY = config('SECRET_KEY') DEBUG = config('DEBUG',cast=bool)
-
-
Note
- Some free server does not allow environment variable setup so it is not configure in this project but for production it is very important to setup environment variable
-
We can use
re_pathin projecturls.pyfrom django.contrib import admin from django.conf import settings from django.conf.urls.static import static from django.views.static import serve from django.urls import path, include, re_path urlpatterns = [ path('admin/', admin.site.urls), path('',include('imageApp.urls')), # for media and static files re_path(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}), re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}) ]
- But problem is using
re_pathis actually gettingstaticandmediafrom the app directory directly not from thestaticfiles - And when using this
re_pathfor bothstaticandmediawe don't needwhitenoisefor static setup - But it is recommended to use
whitenoisestatic setup in production
- But problem is using
-
We can use
staticin projecturls.pyfrom django.contrib import admin from django.conf import settings from django.conf.urls.static import static from django.views.static import serve from django.urls import path, include, re_path urlpatterns = [ path('admin/', admin.site.urls), path('',include('imageApp.urls')) ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
- But problem is using
staticwon't work in production it will not serve the static or media it only works in local
- But problem is using
-
We need to install it whitenoise
-
Then setup it in
settings.pyMIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # This must be added here after SecurityMiddleware & SessionMiddleware ... ] STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
-
Now static file setup is done but for
mediawe need to add there_pathfrom django.contrib import admin from django.conf import settings from django.conf.urls.static import static from django.views.static import serve from django.urls import path, include, re_path urlpatterns = [ path('admin/', admin.site.urls), path('',include('imageApp.urls')), # for media re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}) ]
Important
- Our main goal is to serve
mediaandstaticfrom the project itself not from external sources this is why we need to do these setup otherwise we could just add those in the remote server production/static/and/media/directly - Now what to use, use
re_pathif you don't want to setup whitenoise - But
whitenoisesetup is recommended
- In
Cpanelcreate a python application - Select python version >= 3.10 (for django version 5)
- Add
Application root - Select domain in
Application URLand set the url - Now click on
Create - Go to the
Application rootpath- Edit
passenger_wsgi.pyadd the below line and save itfrom imageProject.wsgi import application# here imageProject is the project name
- Upload project with
requirements.txt
- Edit
- Now again go to the python application and add
requirements.txtinConfiguration files(Save and run pip install) - Now in
Execute python scriptrun this:manage.py collectstatic
- Go to render and select web service from New tab
- Select GitHub repo of the project
- Now in project setting page write Project Name (unique)
- Select Region, Branch
- Set Build command
pip install -r requirements.txt - Set start command
gunicorn imageProject.wsgi:applicationhere
imageProjectis the project name - Choose Instance Type
Freeand start deploy. - For static files
py manage.py collectstaticwhich we can't run in free instance so we run it locally and then deploy which is inrender branch
-
Create an account and login to PythonAnywhere
-
Go to
Consolestab and openbash -
Now cleanup current files and directory
rm -rf ~/* rm -rf ~/.??*
Warning
- This
rmcommand is use to delete files,folders permanently so make sure it is done carefully - We are deleting everything cause we will setup it from the very beginning with our uploaded file on
PythonAnywhere - DO NOT RUN THOSE COMMAND IN OTHER CONSOLE/SERVER
-
Now upload the
deploybranch as zip file-
make sure
djangoversion is5.2.xinrequirements.txtcause in PythonAnywhere latest python version currently is3.10.xwhich does not supportdjangoversion6.0.x. Refs: docs -
We can edit the
requirements.txtinside console usingnanoor directly change it before zipping it and change the version to5.2.xDjango==5.2.14
-
-
Now upload and unzip using the bash console
-
Make sure it will be unzipped in a single directory
-
For example if we unzip
unzip imageProject.zipoutput will be insideimageProjectdirectory -
To ensure this we can open the zip file and see if the contents are in single folder or not
-
Otherwise we have to mention directory name
unzip imageProject.zip -d imageProject
-
Important
- Check the python version if it is
3.10.xwe can create the.venvand install required packages fromrequirements.txt - If python version is not
3.10.xcontinue below
-
Now go to
Webtab -
Select
Manual configuration (including virtualenvs) -
Select
Python 3.10.x -
Add source code path
/home/aatansen/imageProject -
Now we have to configure
WSGI configuration file:/var/www/aatansen_pythonanywhere_com_wsgi.py-
We already have this in our project called
wsgi.pyso we can use it in theaatansen_pythonanywhere_com_wsgi.pywhere first we need to get the path where our project is thenimportthe applicationimport sys sys.path.append('/home/aatansen/imageProject') # path of the project from imageProject.wsgi import application
-
-
Now Create virtual environment
-
Open new bash in
Consolestab -
Make sure python version is
3.10.xpython --version
-
Now create virtual environment named
.venvpython -m venv .venv
-
Activate it
source .venv/bin/activate -
Install
requirements.txtpip install -r requirements.txt
-
-
Add its path in
Virtualenv: /home/aatansen/.venv -
Reload the site and it is done
- Using Serveo
- First run the project
http://127.0.0.1:8000/ ssh -R 80:localhost:8000 serveo.net- To use unique subdomain, need to generate a key
ssh-keygen -t ed25519ssh -R <unique subdomain>:80:<your local host>:<your local port> serveo.net- Example:
ssh -R youruniquesubdomain:80:localhost:8000 serveo.net - Add that domain in
ALLOWED_HOSTSand includeCSRF_TRUSTED_ORIGINS = ['https://youruniquesubdomain.serveo.net']insettings.py
- Now a login prompt to
serveowill be given; use google/github to login - Rerun
ssh -R youruniquesubdomain:80:localhost:8000 serveo.net, now it will work
- First run the project
- Using pinggy
- First run the project
http://127.0.0.1:8000/ - Go to pinggy dashboard
- Copy the ssh of
HTTP(S) Tunneland make sure to change the port to8000 - After running the command give a password
- Now a domain will be provided by pinggy to access
- First run the project
- Using runlocal
- First run the project
http://127.0.0.1:8000/ - Now run
npx runlocal 8000It will install the
runlocaland provide the domain to access
- First run the project
Note
- For custom domain
CSRF_TRUSTED_ORIGINSis important to setup - There are more like this ngrok, localhost.run,localtunnel,cloudflare-tunnel,localxpose,tunnelmole etc
-
Install
django-cleanuppip install django-cleanup- Documentation: Django Cleanup
-
Modify in
settings.py'sINSTALLED_APPSINSTALLED_APPS = [ ... 'django_cleanup.apps.CleanupConfig', ]
Make sure to add it at the bottom
- Now first import the
cleanupinmodels.py-
from django_cleanup import cleanup -
Add
@cleanup.selectbefore class defiedfrom django.db import models from django_cleanup import cleanup # Create your models here. @cleanup.select class UserModel(models.Model): name=models.CharField(max_length=100) profile_image=models.ImageField(upload_to='profile_image') def __str__(self): return self.name
-
Note: To ignore a model we can add
@cleanup_ignore
-
Add this function in
models.pydef user_directory_path(instance, filename): # file will be uploaded to MEDIA_ROOT/user_<id>/<filename> return f"user_{instance.name}_{filename}"
- Here file will be saved as
user_{instance.name}_{file_name}; e.g:user_tansen_1.jpg
- Here file will be saved as
-
Now include this function in
upload_toclass UserModel(models.Model): name=models.CharField(max_length=100) profile_image=models.ImageField(upload_to=user_directory_path) def __str__(self): return self.name
-
Create a custom function
from django.contrib import messages def logout_required(view_func): def wrapper(request, *args, **kwargs): if request.user.is_authenticated: messages.warning(request, "You are already logged in.") return redirect('dashboard') return view_func(request, *args, **kwargs) return wrapper
- Here message is added to show the user that he is already logged in
- Now add this
@logout_requiredbeforesigninandsingupfunction