Install latest version of Python from https://www.python.org/downloads/ which is v3.12.0 at the line of creating this project.
Install Django & Upgrade PIP
python -m pip install Django
python -m pip install --upgrade pip
django-admin startproject <PROJECT_NAME>
python manage.py runserver
Open http://127.0.0.1:8000/ in browser.
python manage.py startapp <APP_OR_MODULE_NAME>
graph TD
S((START)) --> Client
Client[Client - User or Browser]--Request--> Server[Server - Running Python Django];
Server --> URLconf[URLconf]
URLconf --> View3[View]
subgraph views
View1[View 1]
View2[View 2]
View3[View 3]
end
View3 --Response--> Client
URLconfs/Routes: URL-Action mappings which ensure that certain results are "achieved" when certain URLs are entered by the user.
The logic (function or class) that is executed for different URLs (and HTTP methods). The code handles (evaluates, load and prepare data or run any other business logic) requests and returns responses (eg, HTML).
Create a db.squalite3 file in the project root directory
Add <APP_OR_MODULE_NAME> in the <PROJECT_NAME>/settings.py
file
INSTALLED_APPS = [
...
'<APP_OR_MODULE_NAME>'
]
# to create migration file after adding/updating the model files
python manage.py makemigrations
# to apply migrations to the db
python manage.py migrate
# to interact with the db in the shell
python manage.py shell
Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct 2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
# to choose the model you want to interact with
>>> from <APP_OR_MODULE_NAME>.models import <MODEL_NAME>
### create (to save the data to the db) ###
>>> <model_name> = <MODEL_NAME>(<FIELD_NAME_1>="<FIELD_VALUE>", <FIELD_NAME_2>="<FIELD_VALUE>")
>>> <model_name>.save()
>>> <MODEL_NAME>.objects.create(<FIELD_NAME_1>="<FIELD_VALUE>", <FIELD_NAME_2>="<FIELD_VALUE>")
### update (to update existing data in the db) ###
>>> <model_name> = <MODEL_NAME>.objects.all()[0]
>>> <model_name>.age = 25
>>> <model_name>.save()
### delete (to delete existing data in the db) ###
>>> <model_name> = <MODEL_NAME>.objects.all()[0]
>>> <model_name>.delete()
### read (to get data from the db wrt selected model) ###
>>> <MODEL_NAME>.objects.all()
<QuerySet [<MODEL_NAME:...>, ...]> # returns all values
>>> <MODEL_NAME>.objects.get(<UNIQUE_FIELD_NAME>="<FIELD_VALUE>")
<<MODEL_NAME>:...> # always returns single value, only use this on fields that will return single value or else it will throw error. The condition should only match a singel item in the table
>>> from django.shortcuts import get_object_or_404
>>> get_object_or_404(User, pk=user_id) # always returns single value, only use this on fields that will return single value or else it will throw error. The will check using the primary key and if it cant find the data will reurn the 404.html error page from the root template folder
>>> <MODEL_NAME>.objects.filter(<GENERIC_FIELD_NAME>="<FIELD_VALUE>")
<QuerySet [<<MODEL_NAME>:...>, ...]> # returns multiple values, use this on fields that can return multiple values
>>> <MODEL_NAME>.objects.filter(<CHAR_FIELD_NAME>__icontains="<FIELD_VALUE>", <GENERIC_FIELD_NAME>="<FIELD_VALUE>", ...)
<QuerySet [<<MODEL_NAME>:...>, ...]> # returns multiple values, use this on fields that can return multiple values, filters are AND type.
>>> from django.db.models import Q
>>> <MODEL_NAME>.objects.filter(Q(<CHAR_FIELD_NAME>__icontains="<FIELD_VALUE>") | Q(<INTEGER_FIELD_NAME>__lt="<FIELD_VALUE>") | ...)
<QuerySet [<MODEL_NAME:...>, ...]> # returns multiple values, use this on fields that can return multiple values, filters are OR type.
>>> from django.db.models import Q
>>> <MODEL_NAME>.objects.filter(Q(<CHAR_FIELD_NAME>__icontains="<FIELD_VALUE>") | Q(<INTEGER_FIELD_NAME>__lt="<FIELD_VALUE>"), Q(<GENERIC_FIELD_NAME>="<FIELD_VALUE>"))
<QuerySet [<MODEL_NAME:...>, ...]> # returns multiple values, use this on fields that can return multiple values, filters are OR and AND type. `|` is OR, `,` is AND. AND filter can be used with OR without wrapping it in Q() but it has to come at the end or else it will throw error.
>>> data = <MODEL_NAME>.objects.filter(<GENERIC_FIELD_NAME>="<FIELD_VALUE>")
>>> print(data) # this is more performant because django caches the data and if this is printed muktiple times it only hits the db once unless the db data has changed, which is not the case if we directly do `print(<MODEL_NAME>.objects.filter(<GENERIC_FIELD_NAME>="<FIELD_VALUE>"))`
python manage.py createsuperuser
Username (leave blank to use 'anupk'): <USERNAME>
Email address: <EMAIL>
Password: <PASSWORD>
Password (again): <PASSWORD>
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
python manage.py shell
Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct 2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from user.models import User, PhoneNo, Passport, Access
>>> ab = User.objects.get(pk="1")
>>> ab
<User: Absinthe Minded ([email protected]) - 28 - absinthe-minded>
>>> ph1 = PhoneNo(country_code="+91", number="9866098765", user=ab)
>>> ph1.save()
>>> ph11 = PhoneNo.objects.get(pk="1")
>>> ph11.user
<User: Absinthe Minded ([email protected]) - 28 - absinthe-minded>
>>> p = Passport(number="3518561", user=ab)
>>> p.save()
>>> PhoneNo.objects.filter(user__age="28")
<QuerySet [<PhoneNo: PhoneNo object (1)>]>
>>> PhoneNo.objects.filter(user__age__gt="25")
<QuerySet [<PhoneNo: PhoneNo object (1)>]>
>>> ab3 = User.objects.get(pk="1")
>>> ab3.phone_nos.all()
<QuerySet [<PhoneNo: PhoneNo object (1)>]>
>>> ab3.phone_nos.get(country_code="+91")
<PhoneNo: PhoneNo object (1)>
>>> am = User.objects.get(pk="1")
>>> a1 = Access(type="READ")
>>> am.access.add(a1)
>>> a1.save()
>>> am.access.add(a1)
Sometimes, you might have two models that depend on each other - i.e. you end up with a circular relationship.
Or you have a model that has a relation with itself.
Or you have a model that should have a relation with some built-in model (i.e. built into Django) or a model defined in another application.
Below, you find examples for all three cases that include Django's solution for these kinds of "problems": Lazy relationships. You can also check out the official docs in addition.
- Two models that have a circular relationship
class Product(models.Model):
# ... other fields ...
last_buyer = models.ForeignKey('User')
class User(models.Model):
# ... other fields ...
created_products = models.ManyToManyField('Product')
In this example, we have multiple relationships between the same two models. Hence we might need to define them in both models. By using the model name as a string instead of a direct reference, Django is able to resolve such dependencies.
- Relation with the same model
class User(models.Model):
# ... other fields ...
friends = models.ManyToManyField('self')
The special self keyword (used as a string value) tells Django that it should form a relationship with (other) instances of the same model.
- Relationships with other apps and their models (built-in or custom apps)
class Review(models.Model):
# ... other fields ...
product = models.ForeignKey('store.Product') # '<appname>.<modelname>'
You can reference models defined in other Django apps (no matter if created by you, via python manage.py startapp or if it's a built-in or third-party app) by using the app name and then the name of the model inside the app.
# urls.py
from . import views
urlpatterns = [
path("", views.SampleView.as_view(), name="all-samples-path"),
]
# views.py
from django.views import View
class SampleView(View):
def get(self, request):
return render(request, "sample/sample.html", {
"samplae_data": data
})
def post(self, request):
# urls.py
from . import views
urlpatterns = [
path("", views.SampleView.as_view(), name="all-samples-path"),
]
# views.py
from django.views.generic.base import TemplateView
class SampleView(TemplateView):
template_name = "sample/sample.html"
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
sample_id = kwargs["id"] # id passes as param
context = super().get_context_data(**kwargs)
context["template_data"] = "some data to show in template"
return context
# urls.py
from . import views
urlpatterns = [
path("", views.SampleView.as_view(), name="all-samples-path"),
]
# views.py
from django.views.generic import ListView
class SampleView(ListView):
template_name = "sample/sample.html"
model = SampleModel
context_object_name = "samples" # use in tample to loop over the list data
def get_queryset(self):
base_query = super().get_query_set()
data = base_query.filter(rating__gt=4)
return data
# urls.py
from . import views
urlpatterns = [
path("<int:pk>", views.SampleView.as_view(), name="single-sample-path"),
]
# views.py
from django.views.generic import DetailView
from .models import SampleModel
class SampleView(DetailView):
template_name = "sample/sample.html"
model = SampleModel
context_object_name = "sample" # sets the model name or `object` and takes the get context from the param in urls set as `samples/<int:pk>`
<!-- sample.html -->
<form method="POST" action="/">
{% csrf_token %} {% comment %} {{ form }} {% endcomment %} {% for field in
form %}
<div class="form-control {% if field.errors %} errors {% endif %}">
{{ field.label_tag }} {{ field }} {{ field.errors }}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
# urls.py
from . import views
urlpatterns = [
path("<int:pk>", views.SampleView.as_view(), name="single-sample-path"),
]
# views.py
from django.views.generic.edit import FormView
from .forms import SampleForm
class SampleView(FormView):
form_class = SampleForm
template_name = "sample/sample.html"
success_url = "/success"
def form_valid(self, form):
form.save()
return super().form_valid(form)
<!-- sample.html -->
<form method="POST" action="/">
{% csrf_token %} {% comment %} {{ form }} {% endcomment %} {% for field in
form %}
<div class="form-control {% if field.errors %} errors {% endif %}">
{{ field.label_tag }} {{ field }} {{ field.errors }}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
# urls.py
from . import views
urlpatterns = [
path("<int:pk>", views.SampleView.as_view(), name="single-sample-path"),
]
# views.py
from django.views.generic.edit import CreateView
from .forms import SampleForm
from .models import SampleModel
class SampleView(CreateView):
model = SampleModel
form_class = SampleForm # optional or set fields like below, but this gives more control as we cannot set label and all here ike we can in Custom Form Models
# fields = "__all__" # same as custom SampleForm
template_name = "sample/sample.html"
success_url = "/success"
https://docs.djangoproject.com/en/4.2/ref/class-based-views/generic-editing/
# urls.py
from . import views
urlpatterns = [
path("", views.CreateProfile.as_view(), name="create-profile-path"),
path("list", views.ViewProfile.as_view(), name="view-profile-path")
]
<!-- templates/profile/index.html -->
<form action="/profile/" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="image" />
<button>Upload</button>
</form>
# views.py
from django.views import View
from django.http import HttpResponseRedirect
store_file(file):
with open("temp/image.jpeg", "wb+") as dest:
for chunk in file.chunks()
dest.write(chunk)
class CreateProfileView(View):
def get(self, request):
return render(request, "profile/index.html")
def post(self, request):
store_file(request.FILES["image"])
return HttpResponseRedirect("/profile")
<!-- templates/profile/index.html -->
<form action="/profile/" method="POST" enctype="multipart/form-data">
{% csrf_token %} {{ form }}
<button>Upload</button>
</form>
# forms.py
from django import forms
class ProfileForm(forms.Form):
user_image = forms.FileField()
# views.py
from django.views import View
from django.http import HttpResponseRedirect
from .forms import ProfileForm
store_file(file):
with open("temp/image.jpeg", "wb+") as dest:
for chunk in file.chunks()
dest.write(chunk)
class CreateProfileView(View):
def get(self, request):
form = ProfileForm()
return render(request, "profile/index.html", {
"form": form
})
def post(self, request):
submitted_form = ProfileForm(request.POST, request.FILES)
if (submitted_form.is_valid()):
store_file(request.FILES["image"])
return HttpResponseRedirect("/profile")
return render(request, "profile/index.html", {
"form": submitted_form
})
<!-- templates/profile/index.html -->
<form action="/profile/" method="POST" enctype="multipart/form-data">
{% csrf_token %} {{ form }}
<button>Upload</button>
</form>
# models.py
from django.db import models
class Profile(models.Model):
image = models.FileField(upload_to="files") # files folder will be created in MEDIA_ROOT
# image = models.ImageField(upload_to="images") # django will only accespt images and not pdfs and docs # need to install Pillow "python -m pip insll Pillow"
# settings.py
MEDIA_ROOT = BASE_DIR / "uploads"
MEDIA_URL = "/user-media/"
# forms.py
from django import forms
class ProfileForm(forms.Form):
user_image = forms.FileField()
# user_image = forms.ImageField()
# views.py
from django.views import View
from django.http import HttpResponseRedirect
from .forms import ProfileForm
from .models import Profile
class CreateProfileView(View):
def get(self, request):
form = ProfileForm()
return render(request, "profile/index.html", {
"form": form
})
def post(self, request):
submitted_form = ProfileForm(request.POST, request.FILES)
if (submitted_form.is_valid()):
profile = Profile(image=request.FILES["image"])
profile.save()
return HttpResponseRedirect("/profile")
return render(request, "profile/index.html", {
"form": submitted_form
})
<!-- templates/profile/index.html -->
<form action="/profile/" method="POST" enctype="multipart/form-data">
{% csrf_token %} {{ form }}
<button>Upload</button>
</form>
# models.py
from django.db import models
class Profile(models.Model):
image = models.FileField(upload_to="files") # files folder will be created in MEDIA_ROOT
# image = models.ImageField(upload_to="images") # django will only accespt images and not pdfs and docs # need to install Pillow "python -m pip insll Pillow"
# settings.py
MEDIA_ROOT = BASE_DIR / "uploads"
# views.py
from django,views,generic.edit import CreateView
from .models import Profile
class CreateProfileView(CreateView):
template_name = "profile/index.html"
model = Profile
fields = "__all__"
success_url = "/profiles"
<!-- templates/profile/index.html -->
<ul>
{% for profile in profiles %}
<li>
<img src="{{ profile.image.url }}" />
</li>
{% endfor %}
</ul>
# models.py
from django.db import models
class Profile(models.Model):
image = models.FileField(upload_to="files") # files folder will be created in MEDIA_ROOT
# image = models.ImageField(upload_to="images") # django will only accespt images and not pdfs and docs # need to install Pillow "python -m pip insll Pillow"
# settings.py
MEDIA_ROOT = BASE_DIR / "uploads"
MEDIA_URL = "/user-media/"
# urls.py
from django.conf import settings
from django.contrib import admin
from django.conf.urls.static import static
from django.urls import path, include
urlpatterns = [
path('profile/', include("profile.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # needed to allow django to server files, the mapping of the url to the actual path on the file system is done by this static function call in the root settings urls.py
# forms.py
from django import forms
class ProfileForm(forms.Form):
user_image = forms.FileField()
# user_image = forms.ImageField()
# views.py
from django.views.generic import ListView
from .models import Profile
class ViewProfileView(ListView):
template_name = "profile/index.html"
model = Profile
context_object_name = "profiles"
# settings.py
INSTALLED_APPS = [
'django.contrib.sessions'
]
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware'
]
# urls.py
urlpatterns = [
path("users/<int:user_id>", views.UserSessionView.as_view(), name="specific-user-path-id")
]
# views.py
class UserSessionView(View):
def get(self, request):
user_id = request.POST["user_id"]
loaded_user = User.objects.get(pk=user_id)
saved_session_user_id = self.request.session.get("user_id")
return render(request, "user/user.html", {
"is_user_session_saved": loaded_user.id === saved_session_user_id
})
def post(self, request):
user_id = request.POST["user_id"]
request.session["user_id"] = user_id # saves data to session, dont store objects from db just store primitive values like dictionary
redirect_path = reverse("specific-user-path-id", args=[user_id])
return HttpResponseRedirect(redirect_path)
# settings.py
from os import getenv
INSTALLED_APP = [
...
"storages"
]
SECRET_KEY = getenv("SECRET_KEY", "django-insecure-qds*nqoz^z0@%zqc65fet!w(%=#)-5783lwcdqj!j49!d#svu@")
DEBUG = getenv("IS_DEVELOPMENT", True)
ALLOWED_HOSTS = [getenv("APP_HOST", "localhost")]
STATIC_ROOT = BASE_DIR / "staticfiles"
STATIC_URL = "/static/"
STATICFILES_DIRS = [
BASE_DIR / "static"
]
MEDIA_ROOT = BASE_DIR / "uploads"
MEDIA_URL = "/files/"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": getenv("DB_NAME", BASE_DIR / "db.postgresql"),
"USER": getenv("DB_USER", "root"),
"PASSWORD": getenv("DB_PASSWORD", "toor"),
"HOST": getenv("DB_HOST", "some.hosted.endpoint"),
"PORT": getenv("DB_PORT", "5432")
}
}
AWS_STORAGE_BUCKET_NAME = getenv("AWS_STORAGE_BUCKET_NAME", "django-101")
AWD_S3_REGION = getenv("AWS_STORAGE_BUCKET_NAME", "region")
AWS_ACCESS_KEY_ID = getenv("AWS_ACCESS_KEY_ID", "sdfsfdsfsadfads")
AWS_SECRET_KEY_ACCESS = getenv("AWS_SECRET_KEY_ACCESS", "dsfsdfsdfdsfsdf")
AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com"
STATICFILES_STORARGE = "custom_storages.StaticFileStorage"
DEFAULT_FILE_STORAGE = "custom_storages.MediaFileStorage"
STATICFILES_FOLDER = "static"
MEDIAFILES_FOLDER = "media"
# custom_storages.py
from django.conf import settings
from storages.backends.s3boto3 import S3Boto3Storage
class StaticFileStorage(S3Boto3Storage):
location = settings.STATICFILES_FOLDER
class MediaFileStorage(S3Boto3Storage):
location = settings.MEDIAFILES_FOLDER
# urls.py
from django.conf import settings
from django.contrib import admin
from django.conf.urls.static import static
from django.urls import path, include
urlpatterns = [
path('profile/', include("profile.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
python manage.py collectstatic
# python -m pip freeze > requirements.txt
python -m venv django_101_VM
python -m pip install Django Pillow psycopg2-binary django-storages boto3 # install inside the VM
python -m pip freeze > requirements.txt # run inside the VM
# for elastic beanstalk
# create a folder/file -> .ebextensions/{djangoconfig, static-files.config}
// .ebextensions/djangoconfig
option_settings:
aws:eleasticbeanstalk:container:python:
WSGIPath: <PROJECT_NAME>.wsgi:application
// .ebextensions/static-files.config
option_settings:
aws:eleasticbeanstalk:environment:proxy:staticfiles:
/static: staticfiles
/files: uploads
ZIP these and upload to elastic beanstalk
- uploads/
- templates/
- staticfiles/
- <PROJECT_NAME_FOLDER>/
- <APP_FOLDERS>/
- .ebextensions/
- manage.py
- db.sqlite3
Configure more options Edit and add the Environment Variables and the database Save and create app