0% found this document useful (0 votes)
6 views

Django Notes

Django Notes

Uploaded by

reyan.24n67e
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

Django Notes

Django Notes

Uploaded by

reyan.24n67e
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 8

django terminal commands:

python -m venv venv

.\venv\Scripts\activate

pip install django

django-admin startproject djchat

pip install djangorestframework

cd djchat/

pip install python-dotenv

python manage.py runserver

pip install black

pip install flake8

pip freeze > requirements.txt

python manage.py startapp server

python manage.py startapp account

.\venv\Scripts\activate

python manage.py makemigrations

python manage.py migrate

python manage.py createsuperuser //access admin dashboard

Generate Schema with CLI. (Auto Generate Documentation with DRF-Spectacular)

pip install drf-spectacular

#settings.py
INSTALLED_APPS: {
"drf_spectacular",
...
}

REST_FRAMEWORK = {"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema"}

SPECTACULAR_SETTINGS = {
"TITLE": "Your Project API",
"DESCRIPTION": "Your project description",
"VERSION": "1.0.0",
"SERVE_INCLUDE_SCHEMA": False, # whether we want to make the schema available
for a download
}

python ./manage.py spectacular --color --file schema.yml

#drf spectacular will look at our views look for any endpoints and generate a
schema.
#it is going to generate some metadata which is going to be able to record or
describe the endpoints that we have in our system and we can then utilize this
schema and swagger ui to present the data utilizing the gui.

#urls.py
from django.contrib import admin
from django.urls import path

# SpectacularSwaggerView will provide us the GUI.


from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView

urlpatterns = [
path("admin/", admin.site.urls),
# Allow us to download the schema.
path("api/docs/schema/", SpectacularAPIView.as_view(), name="schema"),
# To access the swaggerUI
path("api/docs/schema/ui/", SpectacularSwaggerView.as_view()),
]

#You will now encounter error when starting up server and visiting root directory
'http://127.0.0.1:8000/'
#Page not found error
#Possible paths defined in urls.py will be listed
#Hence, to access a path without error, you will use specified endpoints i.e
'http://127.0.0.1:8000/api/docs/schema/ui/

Authentication:

#settings.py
REST_FRAMEWORK = {
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
# whenever we build an endpoint or view which has or needs authentication we
are just going to call upon djangos session authentication class, and thats
going to help us authenticate the user, should the user be logged-in and should
we need it to authenticate the user before they can access the endpoint. Hence, we
need to make sure the user is logged in and serve them the data related to
them.
"DEFAULT_AUTHENTICATION_CLASSES": [
'rest_framework.authentication.SessionAuthentication',
],
}

Building API Endpoints.

In DJANGO we have a default router with DRF.


It allows us to automatically generate urls for our API Views. This is why we also
use viewsets.

#server/views.py
from django.shortcuts import render
from rest_framework import viewsets
from rest_framework.response import Response

from .models import Server


from .serializer import ServerSerializer

# Create your views here.


# Two Approaches: Function Based Views and Class Based Views
# We will utilize ViewSets which is a class based view.

# ViewSets is a class that will provide CRUD based operations for a model.
# It acts as a bridge between the model and the serializer allowing us to create a
simple and powerful api with little amount of code.

# Creating an API Endpoint for Filtering Servers by Category


# There are two approaches here we can create an endpoint for every single resource
that needs to be accessed.
# i.e we can create an endpoint for category, all servers related to a particular
user, or specific user's servers.
# this can lead us to having many many endpoints and becomes tough to manage.

# the second approach which we will use is to create an endpoint, but to allow it
to pass in multiple parameters, so we can return different resource based upon the
parameters that are passed in.
class ServerListViewSet(viewsets.ViewSet):
# If we dont sent any parameters i.e the category parameter we are going to
return all of the servers.
queryset = Server.objects.all()

# list function acts as a 'get' request


def list(self, request):
# Capture Category ID passed to this end point and retreive category.
category = request.query_params.get("category")

# Return servers related to category id.


if category:
self.queryset = self.queryset.filter(category=category)

# convert data fetched to json via serializer, created serailizer.py in


server.
serializer = ServerSerializer(self.queryset, many=True)
return Response(serializer.data)

#A serializer must be created by you, call it serializer.py inside server

#server/serializer.py:
from rest_framework import serializers

# Sort of data to expect


from .models import Category, Server

# serializers has a ModelSerializer which enables us to utilize the model


information from django to quickly create a serializer.
class ServerSerializer(serializers.ModelSerializer):

# What model we are using and fields we want serialized and sent to frontend
class Meta:
model = Server
fields = "__all__"

# Register router in urls.py, use djangos default router system.

#djchat/urls.py
from django.contrib import admin
from django.urls import path

# SpectacularSwaggerView will provide us the GUI.


from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from rest_framework.routers import DefaultRouter
from server.views import ServerListViewSet

router = DefaultRouter()
router.register("api/server/select", ServerListViewSet)

urlpatterns = [
path("admin/", admin.site.urls),
# Allow us to download the schema.
path("api/docs/schema/", SpectacularAPIView.as_view(), name="schema"),
# To access the swaggerUI
path("api/docs/schema/ui/", SpectacularSwaggerView.as_view()),
] + router.urls

You may now test the endpoint by visiting the url:


http://127.0.0.1:8000/api/server/select/
or
http://127.0.0.1:8000/api/server/select/?category=1

Filter via category name instead of category id requires a simple modification in


views.py

#server/views.py
class ServerListViewSet(viewsets.ViewSet):
# If we dont sent any parameters i.e the category parameter we are going to
return all of the servers.
queryset = Server.objects.all()

# list function acts as a 'get' request


def list(self, request):
# Capture Category ID passed to this end point and retreive category.
category = request.query_params.get("category")

# Return servers related to category id.


if category:
self.queryset = self.queryset.filter(category__name=category)

# convert data fetched to json via serializer, created serailizer.py in


server.
serializer = ServerSerializer(self.queryset, many=True)
return Response(serializer.data)

Refer to endpoint:
http://127.0.0.1:8000/api/server/select/?category=Cat1

Extending an endpoint.
Lets filter servers by quantity

Here we may use a parameter like the number 10 to specify how many servers to
return.

#server/views.py
class ServerListViewSet(viewsets.ViewSet):
# If we dont sent any parameters i.e the category parameter we are going to
return all of the servers.
queryset = Server.objects.all()

# list function acts as a 'get' request


def list(self, request):
# Capture Category ID passed to this end point and retreive category.
category = request.query_params.get("category")
qty = request.query_params.get("qty") #quantity

# Return servers related to category id.


if category:
self.queryset = self.queryset.filter(category__name=category)

if qty:
self.queryset = self.queryset[: int(qty)]

# convert data fetched to json via serializer, created serailizer.py in


server.
serializer = ServerSerializer(self.queryset, many=True)
return Response(serializer.data)

You may now test on endpoint:


http://127.0.0.1:8000/api/server/select/?category=Cat1&qty=1

Filtering Servers by User

Lets first make our Users table visible in our admin login.

#account/admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .models import Account

# Register your models here.


admin.site.register(Account, UserAdmin)

#server/views.py
class ServerListViewSet(viewsets.ViewSet):
# If we dont sent any parameters i.e the category parameter we are going to
return all of the servers.
queryset = Server.objects.all()

# list function acts as a 'get' request


def list(self, request):
# Capture Category ID passed to this end point and retreive category.
category = request.query_params.get("category")
qty = request.query_params.get("qty")
by_user = request.query_params.get("by_user") == "true"

# Return servers related to category id.


if category:
self.queryset = self.queryset.filter(category__name=category)

if by_user:
user_id = request.user.id
self.queryset = self.queryset.filter(member=user_id)
if qty:
self.queryset = self.queryset[: int(qty)]

# convert data fetched to json via serializer, created serailizer.py in


server.
serializer = ServerSerializer(self.queryset, many=True)
return Response(serializer.data)

Lets also create a new user in terminal


python ./manage.py createsuperuser
Username: admin1

Now lets create server ser4, and associate it with admin1 as its owner and member.

Now we will visit the endpoint:


http://127.0.0.1:8000/api/server/select/?by_user=true

We will not see admin1's server (ser4) but all other servers (ser1, ser2, ser3)
as the current user logged in is admin, not admin 1, we can see this when we visit
the endpoint: http://127.0.0.1:8000/admin/
Emphasis on 'admin'.

Server Associated Channels:


We will assume that if a server is returned than associated channels must be
returned too.

class ChannelSerializer(serializers.ModelSerializer):
class Meta:
model = Channel
fields = "__all__"

class ServerSerializer(serializers.ModelSerializer):
channel_server = ChannelSerializer(many=True)

# What model we are using and fields we want serialized and sent to frontend
class Meta:
model = Server
fields = "__all__"

Filtering Servers and Returning Annotation of the number of members.

We have run a query, in whichwe have the field num_members containing the count of
members in a server: #views.py
'''
if with_num_members:
self.queryset = self.queryset.annotate(num_members=Count("member"))
'''

We are going to pass that data through the serializer. #serializer.py

'''
num_members = serializers.SerializerMethodField()
'''

At the moment django doesnt know that this data we have acquired via the queryset
that is referenced by num_members is related to the new field we have create in
serializer.py above, also num_members.

So, what we need to do is just need to tell django that the data in the queryset
should corelate with num_members field in serializer.py that we want to serialize.
So that data in our queryset should be placed right here.

This will require a function in serializer.py:

class ServerSerializer(serializers.ModelSerializer):
num_members = serializers.SerializerMethodField()
...
def get_num_members(Self, obj):
#this num_members refers to num_members data returned from views.py
queryset.
if hasattr(obj, "num_members"):
return obj.num_members
return None

Now when data is to be serialized and the code hits the line:
num_members = serializers.SerializerMethodField()
django will ask itself, what is num_members, it will fire off the get_num_members
function
and get num_members data from the queryset in views.py.

You may now hit the endpoint:


http://127.0.0.1:8000/api/server/select/?with_num_members=true

One more thing if we do not pass the '?with_num_members=true' parameter into the
url, we dont want to return that field. If we try we get data back something like:

{
{
'id':1,
'num_members: null,
...
}
}

We dont want to return the field as null if not asked for.

What we are going to do is we are going to utilize the 'with_num_members' boolean


true that we are going to pass in and we are going to pass that in to the
serializer via views.py
We are going to pass in the fact that we are trying to utilize this filter into the
serializer. We will pass that in as a context.

#views.py:
serializer = ServerSerializer(self.queryset, many=True, context={"num_members":
with_num_members})

If it exists it will be passed to serializer as true, else false.

Turns out, we can then change an object post serialization as well. For that we
need a built in function: 'to_representation' in serializer.py

def to_representation(self, instance):


data = super().to_representation(instance)
#reference to the key 'with_num_members' boolean value
num_members = self.context.get("num_members")
if not num_members: #if false
data.pop("num_members", None)
return data
Configuring Django for image storage

#settings.py
STATIC_URL = "static/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "media/"

#urls.py
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

You might also like