one-to-many relationship in Django Model

In Django, a one-to-many relationship is typically represented using a ForeignKey field in the model. This allows each instance of the model to be associated with one instance of another model. Here’s an example to illustrate this:

Let’s say you have two models: Author and Book. Each author can write multiple books, but each book is written by only one author. This is a one-to-many relationship from Author to Book.

Here’s how you can define these models in Django:

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    birth_date = models.DateField()

    def __str__(self):
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=200)
    publication_date = models.DateField()
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')

    def __str__(self):
        return self.title

Explanation:

  1. Author Model:
    • name: A CharField to store the author’s name.
    • birth_date: A DateField to store the author’s birth date.
    • __str__: A method to return the author’s name when the model instance is printed.
  2. Book Model:
    • title: A CharField to store the book’s title.
    • publication_date: A DateField to store the book’s publication date.
    • author: A ForeignKey field that creates a many-to-one relationship. Each book is associated with one author.
      • on_delete=models.CASCADE: This means that when the referenced author is deleted, all their books will be deleted as well.
      • related_name='books': This allows you to access all books written by a specific author using author.books.all().

Usage:

To create an author and some books, you might do something like this in the Django shell or a view:

# Creating an author
author = Author.objects.create(name="Jane Austen", birth_date="1775-12-16")

# Creating books for the author
Book.objects.create(title="Pride and Prejudice", publication_date="1813-01-28", author=author)
Book.objects.create(title="Sense and Sensibility", publication_date="1811-10-30", author=author)

# Accessing books written by an author
jane_austen_books = author.books.all()
for book in jane_austen_books:
    print(book.title)

This setup ensures that each book is linked to one author, and you can easily retrieve all books written by a particular author using the related_name specified in the ForeignKey field.

Configure the Admin Settings in Django

Configuring the Admin Settings in Django involves several steps, including customizing the admin interface, registering models, and setting up permissions. Here’s a step-by-step guide to help you get started:

1. Set Up Django Admin

The Django admin site is enabled by default. To ensure it is set up correctly, include the django.contrib.admin app in your INSTALLED_APPS setting in settings.py:

INSTALLED_APPS = [
    ...
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    ...
]

2. Create a Superuser

To access the admin site, you need a superuser account. Create one using the following command:

python manage.py createsuperuser

Follow the prompts to set up a username, email, and password.

3. Register Models

Register your models to make them available in the admin interface. Open admin.py in your app directory and register your models:

from django.contrib import admin
from .models import YourModel

admin.site.register(YourModel)

4. Customize Admin Interface

You can customize the admin interface for each model by creating a model admin class:

from django.contrib import admin
from .models import YourModel

class YourModelAdmin(admin.ModelAdmin):
    list_display = ('field1', 'field2', 'field3')  # Fields to display in the list view
    search_fields = ('field1', 'field2')           # Fields to search in the search bar
    list_filter = ('field3',)                      # Fields to filter in the sidebar

admin.site.register(YourModel, YourModelAdmin)

5. Set Up Permissions

Django admin provides a default set of permissions (add, change, delete, view). You can manage these permissions through the admin interface or by using Django’s permission system:

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from .models import YourModel

content_type = ContentType.objects.get_for_model(YourModel)
permission = Permission.objects.create(
    codename='can_publish',
    name='Can Publish Posts',
    content_type=content_type,
)

Assign permissions to a user or group:

from django.contrib.auth.models import User, Group

user = User.objects.get(username='yourusername')
group = Group.objects.get(name='yourgroup')

# Assign to user
user.user_permissions.add(permission)

# Assign to group
group.permissions.add(permission)

References
https://docs.djangoproject.com/en/5.0/ref/django-admin/
https://docs.djangoproject.com/en/5.0/ref/contrib/admin/

null vs blank Field in Django Model

In Django models, the terms blank and null are used to define the behavior of fields at both the application (validation) and database levels. Here’s a detailed comparison:

blank

  • Definition: blank=True specifies whether the field is allowed to be empty in forms.
  • Behavior: This is strictly a validation feature. If blank=True, Django will allow the field to be empty in forms and during model validation. If blank=False, the field is required.
  • Usage: Commonly used for form validation in Django Admin, serializers, and form classes.
  • Example:
    class MyModel(models.Model):
        name = models.CharField(max_length=100, blank=True)
    

null

  • Definition: null=True specifies whether the database column will accept NULL values.
  • Behavior: This is a database feature. If null=True, Django will store NULL in the database when a field has no value. If null=False, the field cannot have NULL in the database and must have some default or empty value.
  • Usage: Used when you want to explicitly allow NULL values at the database level, typically for non-string fields.
  • Example:
    class MyModel(models.Model):
        age = models.IntegerField(null=True)
    

Combined Usage

  • String-based fields: For character-based fields such as CharField and TextField, it’s recommended to use blank=True and null=False. This means empty values will be stored as empty strings ('') rather than NULL.
    class MyModel(models.Model):
        description = models.TextField(blank=True, null=False)
    
  • Non-string-based fields: For non-string fields, you may often see both blank=True and null=True to allow both empty values in forms and NULL values in the database.
    class MyModel(models.Model):
        birth_date = models.DateField(blank=True, null=True)
    

Summary

  • blank=True: Allows the field to be empty in forms.
  • null=True: Allows the field to store NULL in the database.
  • Common Pattern:
    • For strings: blank=True, null=False
    • For non-strings: blank=True, null=True

These settings provide flexibility in how you handle empty and null values in your Django models and forms.

References
https://docs.djangoproject.com/en/5.0/ref/models/fields/

editable Field in Django Model

In Django, if you want to make a model field non-editable, you can set the editable attribute to False in the model field definition.  If False, the field will not be displayed in the admin or any other ModelForm. They are also skipped during model validation. Default is True.

Here’s an example of how to use editable=False in a Django model:

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)
    is_active = models.BooleanField(default=True, editable=False)

    def __str__(self):
        return self.name

In this example:

  • created_at and updated_at are date-time fields that will automatically be set when the object is created or updated, and they are not editable through forms.
  • is_active is a boolean field that is set to True by default and is not editable through forms.

This setup ensures that these fields are not presented in the admin interface or any other form, thereby preventing users from modifying them directly.

References
https://docs.djangoproject.com/en/5.0/ref/models/fields/#editable

Add a Slugfield & Overwrite Save in Django Model

To add a SlugField and overwrite the save method in a Django model, follow these steps:

  1. Define the SlugField in the Model: Add a SlugField to your model to store the slug.
  2. Overwrite the Save Method: Customize the save method to automatically generate and assign a slug value before saving the object.

Here’s a step-by-step example:

Step 1: Install Django Extensions (Optional)

If you want to use the slugify function from Django Extensions, install it via pip:

pip install django-extensions

Step 2: Modify Your Model

from django.db import models
from django.utils.text import slugify

class MyModel(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True, blank=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            # Generate a unique slug
            self.slug = slugify(self.name)
            # Ensure the slug is unique
            unique_slug = self.slug
            num = 1
            while MyModel.objects.filter(slug=unique_slug).exists():
                unique_slug = f'{self.slug}-{num}'
                num += 1
            self.slug = unique_slug
        super(MyModel, self).save(*args, **kwargs)

    def __str__(self):
        return self.name

Explanation:

  1. SlugField Definition:
    slug = models.SlugField(unique=True, blank=True)
    
    • unique=True ensures that each slug is unique.
    • blank=True allows the field to be empty in the form (the slug will be generated automatically if not provided).
  2. Overwriting the Save Method:
    • The save method is overridden to generate a slug if it doesn’t exist.
    • slugify(self.name) generates a slug from the name field.
    • A while loop ensures the slug is unique by appending a number if a conflict is found.
    • The super(MyModel, self).save(*args, **kwargs) call saves the model instance.

Optional: Using Django Extensions (if installed)

If you installed Django Extensions, you can use its slugify function instead of the one from Django’s utilities:

from django_extensions.db.fields import AutoSlugField

class MyModel(models.Model):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(populate_from='name', unique=True)

    def __str__(self):
        return self.name

This approach simplifies the slug generation and ensures uniqueness using the AutoSlugField.

With these steps, you can add a SlugField and overwrite the save method in your Django model to automatically generate and ensure unique slugs for your model instances.

Query Data in Django Model

Setting Up a Django Model

First, ensure you have a Django model defined. For example, let’s say you have a model called Book:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()
    isbn = models.CharField(max_length=13, unique=True)

    def __str__(self):
        return self.title

Querying Data

1. Retrieving All Records

To retrieve all records of the Book model:

books = Book.objects.all()

2. Filtering Records

To filter records, you can use the filter method. For example, to get all books by a specific author:

books_by_author = Book.objects.filter(author='John Doe')

You can also chain multiple filters:

recent_books = Book.objects.filter(author='John Doe', published_date__year=2023)

3. Retrieving a Single Record

To retrieve a single record, you can use the get method. This is useful when you are sure the query will return only one result:

book = Book.objects.get(isbn='1234567890123')

Note: get will raise a DoesNotExist exception if no record is found, and a MultipleObjectsReturned exception if more than one record is found.

4. Excluding Records

To exclude certain records, use the exclude method:

non_recent_books = Book.objects.exclude(published_date__year=2023)

5. Ordering Records

To order records, use the order_by method:

ordered_books = Book.objects.order_by('published_date')

To order in descending order:

ordered_books_desc = Book.objects.order_by('-published_date')

6. Limiting Querysets

To limit the number of results returned, you can use Python’s array slicing:

limited_books = Book.objects.all()[:10]

7. Aggregating Data

To perform aggregation, use the aggregate method along with Django’s aggregation functions like Count, Max, Min, Avg, and Sum:

from django.db.models import Avg

average_published_year = Book.objects.aggregate(Avg('published_date__year'))

8. Using Q Objects for Complex Queries

For more complex queries, such as OR conditions, use Q objects:

from django.db.models import Q

books = Book.objects.filter(Q(author='John Doe') | Q(author='Jane Doe'))

9. Raw SQL Queries

If needed, you can execute raw SQL queries:

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("SELECT * FROM myapp_book WHERE author = %s", ['John Doe'])
    books = cursor.fetchall()

Or use raw manager method:

books = Book.objects.raw('SELECT * FROM myapp_book WHERE author = %s', ['John Doe'])

References
https://docs.djangoproject.com/en/5.0/topics/db/queries/

CRUD Operations in Django Model

In myapp/models.py, define a simple model:

from django.db import models

class Item(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

Run the migrations to create the database schema:

python manage.py makemigrations
python manage.py migrate

In myapp/views.py, create views for handling CRUD operations:

from django.shortcuts import render, get_object_or_404, redirect
from .models import Item
from .forms import ItemForm

def item_list(request):
    items = Item.objects.all()
    return render(request, 'myapp/item_list.html', {'items': items})

def item_detail(request, pk):
    item = get_object_or_404(Item, pk=pk)
    return render(request, 'myapp/item_detail.html', {'item': item})

def item_create(request):
    if request.method == "POST":
        form = ItemForm(request.POST)
        if form.is_valid():
            item = form.save()
            return redirect('item_detail', pk=item.pk)
    else:
        form = ItemForm()
    return render(request, 'myapp/item_form.html', {'form': form})

def item_update(request, pk):
    item = get_object_or_404(Item, pk=pk)
    if request.method == "POST":
        form = ItemForm(request.POST, instance=item)
        if form.is_valid():
            item = form.save()
            return redirect('item_detail', pk=item.pk)
    else:
        form = ItemForm(instance=item)
    return render(request, 'myapp/item_form.html', {'form': form})

def item_delete(request, pk):
    item = get_object_or_404(Item, pk=pk)
    if request.method == "POST":
        item.delete()
        return redirect('item_list')
    return render(request, 'myapp/item_confirm_delete.html', {'item': item})

 

Create a Django Model

Creating a Django model involves defining a class that inherits from models.Model and specifying various fields. Here’s a step-by-step guide to create a Django model with common fields:

  1. Install Django (if you haven’t already):
    pip install django
    
  2. Start a Django Project:
    django-admin startproject myproject
    cd myproject
    
  3. Create an App:
    python manage.py startapp myapp
    
  4. Define the Model: Open the models.py file in your app (myapp/models.py) and define your model. Here’s an example of a Book model:
    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=200)
        author = models.CharField(max_length=100)
        publication_date = models.DateField()
        isbn = models.CharField(max_length=13, unique=True)
        price = models.DecimalField(max_digits=6, decimal_places=2)
        stock = models.PositiveIntegerField()
        description = models.TextField()
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
    
        def __str__(self):
            return self.title
    
  5. Add the App to Project Settings: Add your app to the INSTALLED_APPS list in the settings.py file of your project (myproject/settings.py):
    INSTALLED_APPS = [
        ...
        'myapp',
        ...
    ]
    
  6. Make Migrations: Create migrations for your model. Migrations are Django’s way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema.
    python manage.py makemigrations myapp
    
  7. Migrate the Database: Apply the migrations to your database.
    python manage.py migrate
    
  8. Register the Model in the Admin Site: To make your model visible on the admin site, you need to register it. Open admin.py in your app (myapp/admin.py) and register your model:
    from django.contrib import admin
    from .models import Book
    
    admin.site.register(Book)
    
  9. Run the Development Server: Start the development server to see your changes.
    from django.contrib import admin
    from .models import Book
    
    admin.site.register(Book)
    
  10. Create a Superuser (if you haven’t already): To access the admin site, you need a superuser. Create one with the following command:
    python manage.py createsuperuser
    

Now, you can log in to the Django admin site at http://127.0.0.1:8000/admin/, add some Book entries, and manage them.

References
https://docs.djangoproject.com/en/5.0/topics/db/models/
https://docs.djangoproject.com/en/5.0/ref/models/fields/

Partial Templates in Django

Creating a Partial Template

  1. Create the Partial Template File: Create a separate HTML file for the partial template. For instance, you might create a file called _header.html for the header of your web pages.
    <!-- templates/partials/_header.html -->
    <header>
        <h1>My Website Header</h1>
        <nav>
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/about/">About</a></li>
                <li><a href="/contact/">Contact</a></li>
            </ul>
        </nav>
    </header>
    
  2. Include the Partial Template in Your Main Template: Use the {% include %} template tag to include the partial template in your main templates.
    <!-- templates/base.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>My Website</title>
    </head>
    <body>
        {% include "partials/_header.html" %}
        
        <main>
            {% block content %}
            <!-- Main content goes here -->
            {% endblock %}
        </main>
        
        <footer>
            <p>&copy; 2024 My Website</p>
        </footer>
    </body>
    </html>
    
  3. Extending the Base Template: If you are using a base template that other templates will extend, make sure to extend it properly in your child templates.
    <!-- templates/home.html -->
    {% extends "base.html" %}
    
    {% block content %}
    <h2>Welcome to My Website!</h2>
    <p>This is the homepage.</p>
    {% endblock %}

Using Context in Partial Templates

If you need to pass context variables to a partial template, you can include it with additional context using the with keyword.

  1. Update the Partial Template:
    <!-- templates/partials/_header.html -->
    <header>
        <h1>{{ site_name }}</h1>
        <nav>
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/about/">About</a></li>
                <li><a href="/contact/">Contact</a></li>
            </ul>
        </nav>
    </header>
    
  2. Include the Partial Template with Context:
    <!-- templates/base.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{ title }}</title>
    </head>
    <body>
        {% include "partials/_header.html" with site_name="My Awesome Website" %}
        
        <main>
            {% block content %}
            <!-- Main content goes here -->
            {% endblock %}
        </main>
        
        <footer>
            <p>&copy; 2024 My Awesome Website</p>
        </footer>
    </body>
    </html>
    

By breaking your templates into partials and using the {% include %} tag, you can keep your templates clean, modular, and easy to manage. This approach is particularly useful for repetitive components like headers, footers, navigation bars, and sidebars.

Template Inheritance in Django

Basic Concepts

  1. Base Template: A general template that includes common elements (like headers, footers, and navigation bars) used across multiple pages.
  2. Block Tags: Special tags in Django templates that define sections of the template that can be overridden by child templates.

Steps to Implement Template Inheritance

1. Create a Base Template

First, create a base template that includes the common layout for your website. For example, base.html:

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}My Site{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}">
</head>
<body>
    <header>
        <h1>Welcome to My Site</h1>
    </header>

    <nav>
        <ul>
            <li><a href="{% url 'home' %}">Home</a></li>
            <li><a href="{% url 'about' %}">About</a></li>
            <li><a href="{% url 'contact' %}">Contact</a></li>
        </ul>
    </nav>

    <div class="content">
        {% block content %}{% endblock %}
    </div>

    <footer>
        <p>&copy; 2024 My Site</p>
    </footer>
</body>
</html>

2. Create a Child Template

Next, create a child template that extends the base template. For example, home.html:

{% extends 'base.html' %}

{% block title %}Home - My Site{% endblock %}

{% block content %}
    <h2>Home Page</h2>
    <p>Welcome to the home page of my awesome site!</p>
{% endblock %}

3. Render the Template in Views

In your Django views, render the child template. For example, in views.py:

from django.shortcuts import render

def home(request):
    return render(request, 'home.html')

4. URL Configuration

Ensure you have the appropriate URL configuration in urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    # other paths
]

Key Points to Remember

  • {% extends 'base.html' %}: This tag is used in the child template to specify the base template it extends.
  • Block Tags ({% block content %}{% endblock %}): Define sections in the base template that can be overridden by child templates.
  • Static Files: Use the {% static %} template tag to include static files like CSS and JavaScript.

Example Directory Structure

Here’s an example of what your directory structure might look like:

myproject/
    myapp/
        templates/
            base.html
            home.html
        views.py
        urls.py
    myproject/
        settings.py
        urls.py
        wsgi.py

By using template inheritance, you can efficiently manage and update the layout and design of your website while ensuring consistency across different pages.