image
Feb. 24, 2023

Working with relational data in Django: ForeignKey, OneToOneField and ManyToManyField

Feb. 24, 2023

In web applications, it's common to work with data that has relationships between different entities. Django provides an elegant way of handling relational data through its Object-Relational Mapping (ORM) system. This system allows you to create, query, update, and delete related data effortlessly, without writing complex SQL queries.

 

In this blog post, we will explore the different types of relationships available in Django and learn how to work with them using ForeignKey, OneToOneField, and ManyToManyField. We will set up an example to illustrate the concepts, focusing on the relationships between countries, their capitals, and other cities. By the end of this post, you will have a better understanding of how to work with relational data in Django and how to display it using templates and Bootstrap CSS framework.

 

Understanding Models relationships

 

In Django, relationships between models are represented using special fields that define the type of relationship between the entities. There are three main types of relationships: one-to-many, one-to-one, and many-to-many. These relationships are represented in Django using ForeignKey, OneToOneField, and ManyToManyField, respectively.

 

ForeignKey

 

A ForeignKey field represents a one-to-many relationship between two models. In this relationship, one instance of a model can be related to multiple instances of another model. For example, a country can have many cities, but each city can belong to only one country. To create a ForeignKey relationship, you define a ForeignKey field on the model that has the "many" side of the relationship.

 

OneToOneField

 

A OneToOneField represents a one-to-one relationship between two models. In this relationship, one instance of a model can be related to only one instance of another model. For example, a country can have only one capital, and a capital can belong to only one country. To create a OneToOneField relationship, you define a OneToOneField on one of the models.

 

ManyToManyField

 

A ManyToManyField represents a many-to-many relationship between two models. In this relationship, one instance of a model can be related to multiple instances of another model, and vice versa. For example, students and courses can have a many-to-many relationship, where a student can enroll in multiple courses, and a course can have multiple students. To create a ManyToManyField relationship, you define a ManyToManyField on one of the models.

 

In the next section, we will set up an example using countries, capitals, and cities to demonstrate how to implement these relationships in Django.

 

 

Setting up the example: Countries, Capitals, and Cities

 

To demonstrate the use of ForeignKey, OneToOneField, and ManyToManyField in Django, we will create a simple application that manages countries, capitals, and cities. The relationships between these models are as follows:

 

1. A country can have many cities (one-to-many relationship)

 

2. A country has one capital (one-to-one relationship)

 

3. A city can have multiple tourist attractions, and a tourist attraction can be visited by tourists from multiple cities (many-to-many relationship)

 

In this example, we will use the Country model to represent countries, the Capital model to represent capitals, and the City model to represent other cities. We will also create a TouristAttraction model to represent tourist attractions and their relationship with cities.

 

In the following sections, we will walk through the process of implementing these models in Django and demonstrate how to use Django's ORM to interact with them.

 

 

Implementing the models with Django


To implement the models representing countries, capitals, and cities in Django, we will first create a new Django app and then define the models in the models.py file.

 

Creating the Country model

 

The Country model will have a name field and a one-to-one relationship with the Capital model. We will define this model as follows:

 

from django.db import models

class Country(models.Model):
    name = models.CharField(max_length=100, unique=True)

    def __str__(self):
        return self.name

 

 

Creating the Capital model

 

The Capital model will have a name field, a one-to-one relationship with the Country model, and a many-to-many relationship with the TouristAttraction model. We will define this model as follows:

 

class Capital(models.Model):
    name = models.CharField(max_length=100, unique=True)
    country = models.OneToOneField(Country, on_delete=models.CASCADE)

    def __str__(self):
        return self.name

 

 

Creating the City model

 

The City model will have a name field, a foreign key relationship with the Country model, and a many-to-many relationship with the TouristAttraction model. We will define this model as follows:

 

class City(models.Model):
    name = models.CharField(max_length=100)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)

    def __str__(self):
        return self.name

 

 

Creating the TouristAttraction model

 

Finally, we will create a TouristAttraction model. Each TouristAttraction will have a name and will be associated with multiple cities through a ManyToManyField relationship.

 

class TouristAttraction(models.Model):
    name = models.CharField(max_length=100)
    cities = models.ManyToManyField(City)

    def __str__(self):
        return self.name

 

 

Now that we have defined our models, we need to create the necessary database tables by running the makemigrations and migrate commands in the Django project. Once the tables are created, we can start using Django's ORM to interact with our models.

 

 

Using Django's ORM to interact with the models

 

Django's ORM allows you to interact with your models in a Pythonic way without writing complex SQL queries. In this section, we will demonstrate how to create instances of our models, query related data, update related data, and delete related data.

 

Before we start, let's enter the Django shell to execute the code interactively. To do that, run the following command in your terminal:

 

python manage.py shell

 

 

Once you're in the Django shell, you can import your models and start working with them.

 

Creating instances

 

To create instances of our models, we can use the create method provided by the model's manager. For example, we can create a country, a capital, and a city like this:

 

from myapp.models import Country, Capital, City

country = Country.objects.create(name="Exampleland")
capital = Capital.objects.create(name="Example City", country=country)
city = City.objects.create(name="Another City", country=country)

 

 

Querying related data

 

We can use Django's ORM to query related data. For example, we can get all the cities related to a country like this:

 

cities = City.objects.filter(country=country)

 

 

Or we can get the capital of a country like this:

 

capital = Capital.objects.get(country=country)

 

 

Updating related data

 

We can update related data by updating the fields of the related instances and calling the save method on them. For example, we can update the name of a city like this:

 

country_1 = country.objects.get(capital=Berlin)

country_1.name = "New Name"
country_1.save()

 

 

Deleting related data

 

We can delete related data by calling the delete method on the related instances. For example, we can delete a city like this:

 

country1.delete()

 


Please note that the delete method will also delete any related instances with a ForeignKey or OneToOneField relationship that have on_delete=models.CASCADE set.

In the next section, we will demonstrate how to display related data in Django templates using Bootstrap CSS framework.

 


Displaying related data in templates


Now that we have our models and data set up, let's display the related data in Django templates. In this section, we will show you how to create templates for displaying the country, capital, and city data, as well as how to use the Bootstrap CSS framework for styling.

 

Using Bootstrap for styling

 

To use Bootstrap in our templates, we first need to include the Bootstrap CSS and JavaScript files in the base.html template. You can either download the files and include them locally or use a CDN. For simplicity, we will use the CDN option. Add the following lines to the head and body sections of your base.html file:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Country, Capital, and City Data</title>
    <!-- Add Bootstrap CSS -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    {% block content %}{% endblock %}
    <!-- Add Bootstrap JS and jQuery -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.3/dist/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

 

 

Creating templates for displaying data

 

Now that we have the Bootstrap framework set up, let's create the templates for displaying our data. We will create a template to display a list of countries and their capitals, and another template to display the cities and tourist attractions for a specific country.

 

Create a template called country_list.html and add the following code:

 

{% extends "base.html" %}

{% block content %}
    <h1>Countries and Capitals</h1>
    <table class="table table-striped">
        <thead>
            <tr>
                <th>Country</th>
                <th>Capital</th>
            </tr>
        </thead>
        <tbody>
            {% for country in countries %}
                <tr>
                    <td>{{ country.name }}</td>
                    <td>{{ country.capital.name }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock %}

 

Create a template called country_detail.html and add the following code:
 

{% extends "base.html" %}

{% block content %}
    <h1>{{ country.name }}</h1>
    <h2>Cities</h2>
    <ul>
        {% for city in country.city_set.all %}
            <li>{{ city.name }}</li>
        {% endfor %}
    </ul>
{% endblock %}

 

 

In your views, you can now render these templates and pass the necessary data to them. For example, you can create a view to display the list of countries and their capitals like this:

 

from django.shortcuts import render
from .models import Country

def country_list(request):
    countries = Country.objects.all()
    return render(request, 'country_list.html', {'countries': countries})

 

 

And you can create a view to display the details of a specific country like this:

 

from django.shortcuts import render, get_object_or_404
from .models import Country

def country_detail(request, country_id):
    country = get_object_or_404(Country, pk=country_id)
    return render(request, 'country_detail.html', {'country': country})

 

 

To display the tourist attractions for each city, modify the country_detail.html template as follows:

 

{% extends "base.html" %}

{% block content %}
    <h1>{{ country.name }}</h1>
    <h2>Cities</h2>
    <ul>
        {% for city in country.city_set.all %}
            <li>
                {{ city.name }}
                <ul>
                    <strong>Tourist Attractions:</strong>
                    {% for attraction in city.touristattraction_set.all %}
                        <li>{{ attraction.name }}</li>
                    {% endfor %}
                </ul>
            </li>
        {% endfor %}
    </ul>
{% endblock %}

 

 

Now you have templates to display a list of countries with their capitals, as well as a detailed view of a specific country with its cities and tourist attractions. The templates use the Bootstrap CSS framework for styling.

 


Conclusion


In this post, we have explored how to work with relational data in Django by discussing ForeignKey, OneToOneField, and ManyToManyField relationships. We have also set up an example with countries, capitals, and cities to demonstrate how to implement these relationships in Django models.

 

We then used Django's ORM to create, query, update, and delete related data. Additionally, we have shown how to display this related data in Django templates, using the Bootstrap CSS framework for styling.

 

By understanding and utilizing Django's powerful features for working with relational data, you can create more complex and efficient web applications. As you continue to build your Django projects, remember to leverage the powerful built-in tools and techniques discussed in this post to handle relationships between your models effectively.

 

Discussion

Your comment

Tags