A Complete Guide to Many‑to‑One Relationships in Django Using ForeignKey

This article explains how to define and work with many‑to‑one relationships in Django using ForeignKey. It covers creating related objects, reverse lookups, moving objects between parents, querying across relationships, using lists and querysets in lookups, circular relationship queries, and understanding deletion behavior with CASCADE. All concepts are demonstrated with practical Python API examples.

ForeignKey, many-to-one, Django ORM, reverse relationsarticle_set, CASCADErelated lookups

~2 min read · Updated Mar 10, 2026

1. Defining a Many‑to‑One Relationship

A many‑to‑one relationship is defined using ForeignKey. In the example below, a Reporter can have many Article objects, but each Article has exactly one Reporter.


class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()

class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

2. Creating Data

Creating Reporter instances:


r = Reporter(first_name="John", last_name="Smith", email="[email protected]")
r.save()

r2 = Reporter(first_name="Paul", last_name="Jones", email="[email protected]")
r2.save()

Creating an Article:


from datetime import date
a = Article(headline="This is a test", pub_date=date(2005, 7, 27), reporter=r)
a.save()

Accessing the related Reporter:


a.reporter
a.reporter.id

ForeignKey requires saved objects

Assigning an unsaved Reporter raises an error:


r3 = Reporter(first_name="John", last_name="Smith", email="[email protected]")
Article.objects.create(..., reporter=r3)  # ValueError

3. Reverse Access: Reporter → Article

Django automatically creates a reverse manager named article_set:


r.article_set.all()

Creating an Article from the reverse side:


new_article = r.article_set.create(
    headline="John's second story",
    pub_date=date(2005, 7, 29)
)

4. Moving an Article Between Reporters

You can reassign an Article to another Reporter using add() on the reverse manager:


r2.article_set.add(new_article2)
new_article2.reporter  # Now Paul Jones

Adding the wrong type raises TypeError:


r.article_set.add(r2)  # TypeError

5. Querying Across ForeignKey Relationships

Filtering Articles by Reporter fields:


Article.objects.filter(reporter__first_name="John")
Article.objects.filter(reporter__first_name="John", reporter__last_name="Smith")

Filtering by primary key or object:


Article.objects.filter(reporter__pk=1)
Article.objects.filter(reporter=1)
Article.objects.filter(reporter=r)

Using lists or querysets:


Article.objects.filter(reporter__in=[r, r2]).distinct()

Article.objects.filter(
    reporter__in=Reporter.objects.filter(first_name="John")
).distinct()

6. Reverse Queries: Article → Reporter


Reporter.objects.filter(article__pk=1)
Reporter.objects.filter(article=a)
Reporter.objects.filter(article__headline__startswith="This").distinct()

Counting with distinct:


Reporter.objects.filter(article__headline__startswith="This").count()
Reporter.objects.filter(article__headline__startswith="This").distinct().count()

7. Circular Relationship Queries

You can chain lookups indefinitely:


Reporter.objects.filter(article__reporter__first_name__startswith="John").distinct()

8. Deletion Behavior (CASCADE)

Because on_delete=models.CASCADE is used, deleting a Reporter deletes all their Articles:


r2.delete()
Article.objects.all()  # Articles belonging to r2 are gone

Deleting via JOIN:


Reporter.objects.filter(article__headline__startswith="This").delete()
Reporter.objects.all()  # Empty
Article.objects.all()   # Empty

Conclusion

Many‑to‑one relationships in Django are simple yet powerful. Using ForeignKey, you can easily navigate between related objects, create new objects from either side, move relationships, and perform complex queries across multiple levels. Django’s automatic reverse managers and expressive lookup syntax make working with relational data intuitive and efficient.

Written & researched by Dr. Shahin Siami

Related Articles

Django Tasks Framework: A Complete Guide to Background Task Execution in Django 6.0

Django 6.0 introduces the Tasks framework, a built‑in system for defining and queuing background work outside the request–response cycle. This article explains how Tasks work, how to configure backends, how to define and enqueue tasks, how context works, and how to integrate third‑party worker systems for production environments.

Continue

Asynchronous Support in Django: A Complete Guide to Async Views, ORM, Middleware, Performance, and Safety

This article explains Django’s asynchronous (async) capabilities, including async views, ASGI support, middleware behavior, async ORM features, performance considerations, handling disconnects, and Django’s async safety protections. It also covers how to use sync_to_async(), async ORM methods, and how to safely run synchronous code in async environments.

Continue

Django System Check Framework: A Complete Guide to Writing, Registering, Running, and Testing System Checks

This article explains Django’s System Check Framework—a powerful mechanism for detecting configuration issues, validating project structure, and ensuring code quality. It covers how checks are executed, how to write custom checks, how messages work, how to register and tag checks, how to extend checks for fields and models, and how to write both unit and integration tests for system checks.

Continue

Django Signals: A Complete Guide to Listening, Connecting, Sending, and Managing Application Events

This article provides a comprehensive explanation of Django’s signal system—an event‑driven mechanism that allows decoupled applications to react to actions occurring elsewhere in the framework. It covers how to define receivers, connect signals, use decorators, handle specific senders, organize signal code, and follow best practices to avoid complexity.

Continue

Understanding Django Settings: Configuration, Environment Management, and Best Practices

This article provides a complete overview of Django’s settings system. It explains how settings files work, how to designate a settings module, how to use settings in your code, how to configure Django manually, how to secure sensitive settings, and how to work with custom default settings. It also covers the role of django.setup() for standalone scripts.

Continue

Serializing and Deserializing Django Objects: A Complete Guide to Django’s Serialization Framework

This article explains Django’s serialization framework, including how to serialize and deserialize model instances, work with subsets of fields, handle inherited models, use different serialization formats (JSON, XML, YAML, JSONL), and understand how relational fields are represented. It also covers DeserializedObject behavior and common pitfalls.

Continue