Django Cheat Sheet

steps taken from: https://tutorial.djangogirls.org/en/django_start_project/

start venv

/home/user/dev/myblog

virtualvenv venv

. venv/bin/activate

install django

pip install django

start new project

django-admin startproject myBlog

review myBlog/settings.py, DB settings etc

create database

python manage.py migrate

start webserver

python manage.py runserver

check the URL generated to see if its running

create new application under your project -- example, myBlog/blog

python manage.py startapp blog

a new 'blog' dir is created under project path

edit 'settings.py' and add your applicatoin to INSTALLED_APPS parameter

INSTALLED_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'blog'

]

edit models.py, add this (replace out of box contents)

from django.db import modelsfrom django.utils import timezone
class Post(models.Model):
  author = models.ForeignKey('auth.User')  title = models.CharField(max_length=200)  text = models.TextField()  created_date = models.DateTimeField(default=timezone.now)  published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
  self.published_date = timezone.now()  self.save()
def __str__(self):
  return self.title

create a DB Migrations file, this will add Blog model to DB

python manage.py makemigrations blog

create the model

python manage.py migrate blog

Create an Admin login page

open blog/admin.py replace contents with this,

from django.contrib import admin from .models import Post  admin.site.register(Post)

create an Admin user

python manage.py createsuperuser

SQL and Queries

Insert / Create

models.py
class Employee(models.Model):  account_id = models.IntegerField(unique=True)  fname = models.CharField()  lname = models.CharField()  age = models.IntegerField()  role = models.ForeignKey(Roles)

create a new Employee row 

## views.pyfrom .models import Employeee = Employee(account_id=234, fname="joe", lname="smith")e.save()

update existing Employee row (search for specific row, then update it)

e = Employee.objects.get(fname="joe")e.fname = "fred"e.save()

Queries

get # of records

Cars.objects.all().count()

distinct / unique count 

Cars.objects.distinct().count()

get distinct values

Cars.objects.values("Chevy").distinct().count()

get datetime YYYY of creation

Cars.objects.dates("created", "year")

Order by

Cars.objects.all().order_by("color")

order by color ascending, brand descending

Cars.objects.all().order_by("color", "-brand")

get first 5 records

Cars,objects.filter(color="red")[:5]

latest / earliest 

Cars.objects.latest("created")  # or earliest 

RAW SQL

pass parameter to raw sql

drinks_low_caffeine = Drink.objects.raw("SELECT * FROM items_drink where caffeine < %s",params=[caffeine_limit]);

If / Then based on Query


from django.db.models import Case, When, Value, CharField
from .models import Product
products = Product.objects.annotate(
   product_type=Case(       When(product_code__startswith='1', then=Value('ELECTRONIC')),       When(product_code__startswith='2', then=Value('FURNITURE')),       default=Value('OTHER'),       output_field=CharField(),   ))

Prefetch Objects

Prefetch Objects: The prefetch_related() function reduces and optimizes the number of database hits.

from django.db.models import Prefetchfrom .models import Author, Book

authors = Author.objects.prefetch_related(   Prefetch('books', queryset=Book.objects.filter(title__contains='Django')))

In the above example, for each author in authors, the related books are prefetched from the database, but only if their title contains 'Django'. This can significantly optimize database queries when dealing with related objects.


F objects

F() Expressions: F() expressions allow you to refer to model field values and perform database operations using them. They can be particularly useful for making atomic updates. 

from django.db.models import Ffrom .models import Product

Product.objects.update(stock=F('stock') - 1)

In this example, the F() expression is used to decrement the stock of all products by one directly in the database, which is more efficient and safe against race conditions.


Queries

get specific row by PK

e = Employee.objects.get(pk=123)

get all rows

e = Employee.objects.all()

search by specific field (WHERE)

e = Employee.objects.filter(fname="joe")

AND query

# Get the Store records that have state 'CA' AND city 'San Diego'Store.objects.filter(state='CA', city='San Diego')

complex AND

queryset = User.objects.filter(    Q(first_name__startswith='R') & Q(last_name__startswith='D')

OR query

from django.db.models import QStore.objects.filter(Q(state='CA') | Q(state='AZ')

AND NOT (starts with R and NOT starts with Z

queryset = User.objects.filter(    Q(first_name__startswith='R') & ~Q(last_name__startswith='Z')

less than or equal to

e = Employee.objects.filter(age__lte=20)

search by case insensitive

e = Employee.objects.get(fname__iexact="joe")

## will match Joe, JoE, joe, JOE

search any row that contains string

e = Employee.objects.get(fname__contains="jo")

search across multiple tables (JOIN)

e = Employee.objects.filter(roles__name="worker")

## joins Employee table with Roles table where role.name=worker

JOIN with Contains

e = Employee.objects.filter(roles__name__contains="work")

EXCLUDE query

# Get the Store records that don't have state 'CA'Store.objects.exclude(state='CA')

NULL query

# Get the Store records that have email NULLStore.objects.filter(email__isnull=True)

Find value from IN list

# Get the Store records that have state 'CA' OR state='AZ'Store.objects.filter(state__in=['CA','AZ'])
# Get the Item records with id 1,2 or 3Item.objects.filter(id__in=[1,2,3])

CONTAINS, STARTSWITH, ENDSWITH

Get the Store records that contain a 'C' anywhere in state (LIKE '%C%')

Store.objects.filter(state__contains='C')

Get the Store records that start with 'San' in city (LIKE 'San%')

Store.objects.filter(city__startswith='San')

Get the Item records that end with 'e' in name (LIKE '%e')

Drink.objects.filter(item__name__endswith='e')

select only certtain fields

qs = Article.objects.only("author")

select all fields EXCEPT these 2

qs = Article.objects.defer("create_date", "rating")

get # of hits from a query

num_of_articles = Article.objects.all().count()

check if query set contains an object

Article.objects.contains(article)

get average 

# Average price across all books, provide default to be returned instead of None if no books exist.

from django.db.models import AvgBook.objects.aggregate(Avg("price", default=0)){'price__avg': 34.35}

get total count

# Total number of books with publisher=BaloneyPress

Book.objects.filter(publisher__name="BaloneyPress").count()73

get Max number

# Max price across all books, provide default to be returned instead of None if no books exist.

from django.db.models import MaxBook.objects.aggregate(Max("price", default=0)){'price__max': Decimal('81.20')}

Create dynamic queryset values with Annotate

ie, create dynamic value service_ok and service_error for any Host that has Services with state=1 (error)

(Service model has FK to Host, Many services > to 1 Host)

from django.db.models import Q, Count
allhosts = Host.objects.annotate(svc_error=Count("service", filter=~Q(service__status=0))).annotate(svc_ok=Count("service", filter=Q(service__status=0))).order_by("name").prefetch_related("service")

in Template can pass the svc dynamic values:

{% for host in allhosts %}
# ok services = {{ host.svc_ok }}
# error services = {{ host.svc_error }}
{% endfor %}

Caching

for frequently accessed queryset data, use a cache, this will store all Articles in a cache for 3600 seconds (1 hour)

from django.core.cache import cachefrom .models import Article
def get_article():  cached_data = cache.get("articles")  if cached_data:    return cached_data  data = Article.objects.all()  cache.set("articles", data, 3600)  return data

  

Django Channels

Django Channels is a fantastic tool that extends Django to handle WebSockets, long-poll HTTP, and other asynchronous protocols. While it’s typically associated with real-time communication features, like chat apps, Channels can also be leveraged to manage asynchronous tasks in your Django application. Let’s take a look at how you can exploit this powerful feature.

Running Asynchronous Tasks: Django Channels uses an event-driven architecture powered by ASGI (Asynchronous Server Gateway Interface). This makes it a great tool for managing tasks that could benefit from asynchronous execution. For example, if you have a resource-intensive task that you don’t want to block your server’s response, you can offload that task to Django Channels.

from channels.layers import get_channel_layerfrom asgiref.sync import async_to_sync
channel_layer = get_channel_layer()

def expensive_view(request):
   # Offload the expensive task to the channel layer   async_to_sync(channel_layer.send)('expensive_task', {'type': 'expensive.task'})   return HttpResponse("Task is being processed!")

In the consumer:

class ExpensiveConsumer(AsyncConsumer):   async def expensive_task(self, event):       # Your expensive task here       pass

This will allow your view to quickly respond to the user while the expensive task is processed in the background.


Jinja Templates

custom Template tags

To create a custom template tag, you first need to create a Python module in a Django app and define your custom function there.

# myapp/templatetags/my_custom_tags.py
from django import template

register = template.Library()

@register.filter
def lower(value):  # Converts a string into all lowercase   return value.lower()

In your template, you would load the custom tags and then use them:

{% load my_custom_tags %}<p>{{ my_string|lower }}</p>

Template Context Processors

A context processor is a Python function that takes the request object as an argument and returns a dictionary to add to the context. They’re specified using the TEMPLATE_CONTEXT_PROCESSORS setting and are a fantastic way to make sure certain data is available to all your templates.

Let’s create a context processor that adds the current year to every template:

# myapp/context_processors.py
from datetime import datetime

def current_year(request):   return {'current_year': datetime.now().year}

Make sure you’ve added the context processor to your settings.py:

TEMPLATES = [   {       # ...       'OPTIONS': {           'context_processors': [               # ...               'myapp.context_processors.current_year',           ],       },   },]

Now, you can access the current year in your templates:

<footer>   &copy; {{ current_year }} My Amazing Site</footer>


Security

Clickjacking Protection: Clickjacking is a malicious technique where an attacker tricks a user into clicking something different from what the user perceives, potentially leading to unwanted actions. Django provides a middleware to protect against clickjacking by setting the X-Frame-Options header in HTTP responses. To activate this protection, add 'django.middleware.clickjacking.XFrameOptionsMiddleware' to your MIDDLEWARE settings:

MIDDLEWARE = [   # ...   'django.middleware.clickjacking.XFrameOptionsMiddleware',   # ...]

By default, the header is set to DENY, meaning the page cannot be displayed in a frame. You can adjust this using the X_FRAME_OPTIONS setting.

Host Header Validation: Django uses the host header in the incoming HTTP request to construct URLs in certain cases. However, a maliciously crafted host header could lead to vulnerabilities. From version 1.10.3 onwards, Django validates the host header against the ALLOWED_HOSTS setting and returns a 400 Bad Request response if the host header doesn’t match any pattern in the list.

ALLOWED_HOSTS = ['mywebsite.com', 'www.mywebsite.com']

It’s important to keep this setting up-to-date as your project grows or changes environments.

SECURE_PROXY_SSL_HEADER Setting: If your Django app is behind a proxy that’s serving HTTPS, Django needs to know when a request is secure so it can generate appropriate URLs and avoid redirect loops. In this scenario, you can use the SECURE_PROXY_SSL_HEADER setting. This is a tuple representing a header/value pair that a proxy sets when handling HTTPS requests:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Be cautious with this setting; only use it when you control both the Django app and the proxy, as it can lead to security issues if misconfigured.




Debug

show request data

for key, val in request.POST.items():
  print(key, val)



Static Files

check if Django sees file in Static DIRS

./manage.py findstatic /assets/compiled/css/app.css
django.core.exceptions.SuspiciousFileOperation: The joined path (/assets/compiled/css/app.css) is located outside of the base path component (/home/mreider/dev/python/monitdj/static)