Django - Anton-L-GitHub/Learning GitHub Wiki

Modles

Example data model

class Customer(models.Model):
    MEMBERSHIP_BRONZE = 'B'
    MEMBERSHIP_SILVER = 'S'
    MEMBERSHIP_GOLD = 'G'

    MEMBERSHIP_CHOICES = [
        (MEMBERSHIP_BRONZE, 'Bronze'),
        (MEMBERSHIP_SILVER, 'Silver'),
        (MEMBERSHIP_GOLD, 'Gold'),
    ]
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=255)
    birth_date = models.DateField(null=True)
    membership = models.CharField(
        max_length=1, choices=MEMBERSHIP_CHOICES, default=MEMBERSHIP_BRONZE)

    def __str__(self): 
        return self.first_name

Django ORM

Example queryset

queryset = Product.objects.filter(inventory__lt=10)

And (chaining)

# Use chaining for simple and queries
# Products where inventory < 10 and unit_price < 20
queryset = Product.objects.filter(inventory__lt=10).filter(unit_price__lt=20)

Q-objects (Or, And, Not)

# Products where inventory < 10 OR unit_price < 10  '
queryset = Product.objects.filter(Q(inventory__lt=10) | Q(unit_price__lt=20))

# Products where inventory < 10 AND NOT unit_price < 10
.filter(Q(inventory__lt=10) &~ Q(unit_price__lt=20))
  • Use bitwise
    • | or
    • & and
    • ~ not

F-Objects

# F-ield-objects are for when you want to compare columns
# Products where inventory = unit_price
queryset = Product.objects.filter(inventory=F('unit_price'))

Sorting

# All products sorted by title - ASC order
queryset = Product.objects.order_by('title')

# All products sorted by title - DESC order
.order_by('-title')

# Mutiple arguments
# Most expencive products in title ASC order
.order_by('-unit_price', 'title')

# Reverse last example
.order_by('-unit_price', 'title').reverse()

# Indexing - Returns object right away
.order_by('unit_price')[0]

# Indexing - Returns queryset
.earliest('unit_price')
.latest('unit_price')

# Slicing
.order_by('unit_price')[:5]

Selecting specific fields

# Returns dictionary, does'nt return an object.
queryset = Product.objects.values('id', 'title', 'collection')

# Returns touple.
.values_list('id', 'title', 'collection')

# Returns instance with only attributes 'id' and 'title'.
# Careful! You can accidentally overload the db with queryies, if you handle wrong!  
# Say if you later want 'description' later in a for-loop, then django will need to send a query for all objects.
.only('id', 'title')
# Same but opposite to only, returns instance with all attributes except 'id' and 'title'
.defer('id', 'title') 

Pre-loading other tables

# This pre-loads (join the tables) the collection-table so you don't need to ask the db for each product later on.
# One-to-one joins, one product has one collection
queryset = Product.objects.select_related('collection').all()
# One-to-many join
.prefetch_related('promotions')

Aggregate

Examples
orders_placed = Order.objects.aggregate(Count=Count('id'))

units_sold = OrderItem.objects \
    .filter(product_id=1) \
    .aggregate(units_sold=Sum('quantity'))

orders_placed = Order.objects\
    .filter(customer_id=1)\
    .aggregate(orders_placed=Count('id'))

min_max_avg_collection_3 = Product.objects\
    .filter(collection_id=3)\
    .aggregate(
        max=Max('unit_price'),
        min=Min('unit_price'),
        avg=Avg('unit_price'))

Annotate

# When you wanna ADD attributes to our object when querying them
# Adds a new column 'new_id' and sets it to the original id :)
queryset = Customer.objects.annotate(new_id=F('id'))

Call db-function

# Concatenation, obs do next example instead
queryset = Customer.objects.annotate(
        custom_name_of_field=Func(F('first_name'), Value(' '), F('last_name'), function='CONCAT')
    )
# Same but with a Concat object
queryset = Customer.objects.annotate(
        full_name=Concat('first_name', Value(' '), 'last_name')
    )
# Number of orders for each customer
.annotate(orders_count=Count('order'))
# Collections and count of their products  
.annotate(products = Count('product'))
# Customers with more than 5 orders 
.annotate(orders_count=Count('order')).filter(orders_count__gt=5)
# 

The Admin Site

Register models

Django Admin Site Doc

# Example model to display in admin
@admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ['title', 'unit_price', 'inventory_status']
    list_editable = ['unit_price']
    list_per_page = 10

    @admin.display(ordering='inventory')
    def inventory_status(self, product):
        if product.inventory < 10:
            return 'Low'
        return 'OK'