# select\_related() - what is wrong with my design

**URL:** <https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987>\
**Category:** Using the ORM\
**Created:** [March 12, 2024, 10:33am UTC](https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987 "2024-03-12T10:33:11Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![piotr-kubiak](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/piotr-kubiak/32/19832_2.png) [@piotr-kubiak](https://forum.djangoproject.com/u/piotr-kubiak)\
**Post date:** [March 12, 2024, 10:33am UTC](https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987/1 "2024-03-12T10:33:11Z")

</div>

My model:

```auto
class Foo(models.Model):
    name = models.CharField(unique=True, max_length=50)
    self_foo = models.ForeignKey(to="self", on_delete=models.PROTECT)

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=30 )
    parent_foo = models.ForeignKey(to=Foo, on_delete=models.PROTECT)

```

Lets do some inspections:

```auto
>>> from polls.models import Foo, Bar
>>> print(Bar.objects.all().query)
SELECT "polls_bar"."id", "polls_bar"."name", "polls_bar"."parent_foo_id" FROM "polls_bar"

```

This looks as expected.  
However:

```auto
>>> print(Bar.objects.select_related().query) 
SELECT "polls_bar"."id", "polls_bar"."name", "polls_bar"."parent_foo_id", "polls_foo"."id", "polls_foo"."name", "polls_foo"."self_foo_id", T3."id", T3."name", T3."self_foo_id", T4."id", T4."name", T4."self_foo_id", T5."id", T5."name", T5."self_foo_id", T6."id", T6."name", T6."self_foo_id" FROM "polls_bar"
INNER JOIN "polls_foo" ON ("polls_bar"."parent_foo_id" = "polls_foo"."id")
INNER JOIN "polls_foo" T3 ON ("polls_foo"."self_foo_id" = T3."id")
INNER JOIN "polls_foo" T4 ON (T3."self_foo_id" = T4."id")
INNER JOIN "polls_foo" T5 ON (T4."self_foo_id" = T5."id")
INNER JOIN "polls_foo" T6 ON (T5."self_foo_id" = T6."id")

```

Why there is four extra tables joined in my query? How can I control that? I’d like only one extra join.  
I’ve found the magic setting `max_depth=5` in `django.db.models.sql.query`, but this seems very internal. I now that I can do `Bar.objects.select_related("parent_foo")` to stop this behaviuor, however then I have to specify all other foreing keys I want to include as related in my query.

In reality my model is much bigger, and I want to use build in ModelAdmin, and I really don’t want to go through maintaing select\_related setting in all of my models just to list all FK’s there. Without this, I am very quickly hitting limits such as `jango.db.utils.OperationalError: at most 64 tables in a join` or `too many columns in result set`.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 12, 2024, 11:24am UTC](https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987/2 "2024-03-12T11:24:56Z")

</div>

The issue is the foreign key to `self` in `Foo`.

You can prevent the recursion by specifying the references in the [`select_related`](https://docs.djangoproject.com/en/5.0/ref/models/querysets/#select-related) clause.

e.g., `Bar.objects.select_related('parent_foo').all()`

Be aware that you **never** _need_ to use `select_related`. It’s a performance enhancement, not a requirement. You can selectively use it in each query as needed. If you’ve got a view that only uses 4 of the foreign keys in the query results, then you _can_, if desired, only list those 4. (Or not, your choice.)

Also, if the purpose of the ForeignKey to `self` in `Foo` is to create a tree structure of indeterminate depth, then this is _not_ how you want to do it in a relational database. (If the intent of it is only to allow for a single level, then it’s ok.)

---

<div class="post-metadata">

**Author:** ![piotr-kubiak](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/piotr-kubiak/32/19832_2.png) [@piotr-kubiak](https://forum.djangoproject.com/u/piotr-kubiak)\
**Post date:** [March 12, 2024, 11:33am UTC](https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987/3 "2024-03-12T11:33:53Z")

</div>

> [@KenWhitesell](#):
>
> You can prevent the recursion by specifying the references in the [`select_related`](https://docs.djangoproject.com/en/5.0/ref/models/querysets/#select-related) clause.

This is what I’d rather avoid. As I said, I am using ModelAdmin and don’t want to customize it unless absolutely necessary.

There is only one level of `self` in `Foo`.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 12, 2024, 11:58am UTC](https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987/4 "2024-03-12T11:58:40Z")

</div>

If this is something you’re using in the Admin, then I wouldn’t worry about the select\_related at all.

Or use it selectively, your choice. However, because it is completely optional, you are never _required_ to keep adding entries as your models change.

---

<div class="post-metadata">

**Author:** ![piotr-kubiak](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/piotr-kubiak/32/19832_2.png) [@piotr-kubiak](https://forum.djangoproject.com/u/piotr-kubiak)\
**Post date:** [March 12, 2024, 2:33pm UTC](https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987/5 "2024-03-12T14:33:47Z")

</div>

> [@KenWhitesell](#):
>
> If this is something you’re using in the Admin, then I wouldn’t worry about the select\_related at all.

I have extra attributes in Foo and in Bar, and I am hitting the limits for the number of columns and joins very quickly.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 12, 2024, 2:36pm UTC](https://forum.djangoproject.com/t/select-related-what-is-wrong-with-my-design/28987/6 "2024-03-12T14:36:57Z")

</div>

Then don’t use select\_related. Yes, it causes Django to issue additional queries to retrieve that data, but since this is the admin, it’s not like there are dozens of people using it, so it shouldn’t be a real problem.
