[Django] #34789: Admin filter_horizontal shows item in "Chosen" column after being added through a Foreign Key field of the same model.

39 views
Skip to first unread message

Django

unread,
Aug 21, 2023, 5:45:11 PM8/21/23
to django-...@googlegroups.com
#34789: Admin filter_horizontal shows item in "Chosen" column after being added
through a Foreign Key field of the same model.
-----------------------------------------+------------------------
Reporter: devin13cox | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 1
UI/UX: 1 |
-----------------------------------------+------------------------
Hi there, I noticed a minor frontend bug related to the filter_horizontal
tables in the admin console. Here is what I have:

There is a model called Transition with two fields, source and target:

{{{
source = models.ManyToManyField(State, related_name="transition_source")
target = models.ForeignKey(State, related_name="transition_target",
on_delete=models.CASCADE)
}}}

For the admin console, we set filter_horizontal to include 'source'. Here
is an example of a given state of a Transition, with "test" selected as
Source and "test2" selected as Target.

[[Image(file:///Users/devincox/Desktop/Screenshot%202023-08-21%20at%202.09.51%20PM.png)]]

Now, if I add a new State by clicking the "+" Icon next to the Target
field (let's call it test3), it will add it to both the Target AND the
"Chosen Source":

[[Image(file:///Users/devincox/Desktop/Screenshot%202023-08-21%20at%202.14.24%20PM.png)]]

I will note that upon saving the Transition, it will not actually save
"test3" to the Chosen Source, meaning that this is an issue only from a UI
perspective. After any refresh or save, it will also no longer show in the
Chosen Source column. Additionally, there is no issue going the other
direction (if I add directly using the "+" next to Chosen Source, it will
not appear to set the "Target" field as well, and it will save properly).
Finally, if I were to select another available source (ex. "test2") and
add it to the Chosen Source, it will successfully add "test2" and remove
"test3" without needing a save or refresh.

I believe this is due to the admin conveniently updating all related
fields to include the added object, and therefore displaying it as if it
was selected temporarily until refreshed

Diving into this, I believe the issue is in this file:
django/django/admin/static/admin/js/admin/RelatedObjectLookups.js

In this function: UpdateRelatedSelectOptions, on this query:
{{{
const selectsRelated = document.querySelectorAll(`[data-model-
ref="${modelName}"] select:not(.admin-autocomplete)`);
}}}

My initial guess is that updating the query to not include the "Chosen"
column in filter_horizontal fields would solve this issue (something like
{{{
const selectsRelated = document.querySelectorAll(`[data-model-
ref="${modelName}"] div:not(.selector-chosen) > select:not(.admin-
autocomplete)`);
}}}

Let me know if more context is needed to help reproduce what is going on
here. Thanks!

--
Ticket URL: <https://code.djangoproject.com/ticket/34789>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Aug 21, 2023, 5:45:44 PM8/21/23
to django-...@googlegroups.com
#34789: Admin filter_horizontal shows item in "Chosen" column after being added
through a Foreign Key field of the same model.
-------------------------------+--------------------------------------

Reporter: devin13cox | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 1
-------------------------------+--------------------------------------
Changes (by devin13cox):

* Attachment "Screenshot 2023-08-21 at 2.09.51 PM.png" added.

First Screenshot

Django

unread,
Aug 21, 2023, 5:46:01 PM8/21/23
to django-...@googlegroups.com
#34789: Admin filter_horizontal shows item in "Chosen" column after being added
through a Foreign Key field of the same model.
-------------------------------+--------------------------------------
Reporter: devin13cox | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 1
-------------------------------+--------------------------------------
Changes (by devin13cox):

* Attachment "Screenshot 2023-08-21 at 2.14.24 PM.png" added.

Second Screenshot

Django

unread,
Aug 21, 2023, 5:46:48 PM8/21/23
to django-...@googlegroups.com
#34789: Admin filter_horizontal shows item in "Chosen" column after being added
through a Foreign Key field of the same model.
-------------------------------+--------------------------------------
Reporter: devin13cox | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 1
-------------------------------+--------------------------------------
Description changed by devin13cox:

Old description:

New description:

Hi there, I noticed a minor frontend bug related to the filter_horizontal
tables in the admin console. Here is what I have:

There is a model called Transition with two fields, source and target:

{{{
source = models.ManyToManyField(State, related_name="transition_source")
target = models.ForeignKey(State, related_name="transition_target",
on_delete=models.CASCADE)
}}}

For the admin console, we set filter_horizontal to include 'source'. See
"First Screenshot" for an example of a given state of a Transition, with


"test" selected as Source and "test2" selected as Target.

Now, if I add a new State by clicking the "+" Icon next to the Target


field (let's call it test3), it will add it to both the Target AND the

"Chosen Source" (see "Second Screenshot" for an example).

--

--
Ticket URL: <https://code.djangoproject.com/ticket/34789#comment:1>

Django

unread,
Aug 21, 2023, 6:04:36 PM8/21/23
to django-...@googlegroups.com
#34789: Admin filter_horizontal shows item in "Chosen" column after being added
through a Foreign Key field of the same model.
-------------------------------+--------------------------------------
Reporter: devin13cox | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 1
-------------------------------+--------------------------------------

Comment (by Natalia Bidart):

Hello! Thank you for your report. Could you please post your admin.py
definition as well as your models.py (reduced to this example)? So we can
try to reproduce and triage accordingly. Thanks!

--
Ticket URL: <https://code.djangoproject.com/ticket/34789#comment:2>

Django

unread,
Aug 21, 2023, 6:43:58 PM8/21/23
to django-...@googlegroups.com
#34789: Admin filter_horizontal shows item in "Chosen" column after being added
through a Foreign Key field of the same model.
-------------------------------+--------------------------------------
Reporter: devin13cox | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 1
-------------------------------+--------------------------------------

Comment (by devin13cox):

Replying to [comment:2 Natalia Bidart]:


> Hello! Thank you for your report. Could you please post your admin.py
definition as well as your models.py (reduced to this example)? So we can
try to reproduce and triage accordingly. Thanks!

Of course, here is the model (reduced to the example):


{{{
class Workflow(models.Model):
initial = models.ForeignKey('workflow.State', blank=True, null=True,
related_name="workflow_initial", on_delete=models.SET_NULL)

class Transition(models.Model):


source = models.ManyToManyField(State,
related_name="transition_source")
target = models.ForeignKey(State, related_name="transition_target",
on_delete=models.CASCADE)

class State(models.Model):
label = models.CharField(max_length=255)
}}}

And the admin (also reduced):


{{{
class WorkflowAdmin(SortableAdminBase, admin.ModelAdmin):
inlines = [TransitionInline, ]
fieldsets = (
(None, {
'fields': ["initial"],
}),
)

class TransitionInline(SortableStackedInline, admin.StackedInline):

model = Transition
extra = 0
filter_horizontal = ['source']

fieldsets = (
(' ', {
'classes': ('collapse',),
'fields': ('source', 'target')
}),
)

class StateAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ("label",),
}),
)
}}}

As you can see, the model of interest is Transition and in the admin
console it is represented through as an inline for another model called
Workflow. I tried to remove any extra information to avoid confusion (part
of this removal was my_order fields in case there is confusion as to why
Sortable is being used).

--
Ticket URL: <https://code.djangoproject.com/ticket/34789#comment:3>

Django

unread,
Aug 21, 2023, 8:53:58 PM8/21/23
to django-...@googlegroups.com
#34789: Admin filter_horizontal shows item in "Chosen" column after being added
through a Foreign Key field of the same model.
-------------------------------+------------------------------------
Reporter: devin13cox | Owner: nobody
Type: Bug | Status: new
Component: contrib.admin | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 1
-------------------------------+------------------------------------
Changes (by Natalia Bidart):

* stage: Unreviewed => Accepted


Comment:

Replying to [comment:3 devin13cox]:


> Of course, here is the model (reduced to the example):

Great! Thank you.

> While I don't think that the "Workflow" component (and Inline stacking)
are relevant to this bug -- I kept them there to keep it as close to my
current flow as possible. This should be able to be reproduced without the
workflow element.

Confirmed I was able to reproduce with a reduced example like this:

{{{#!python
from django.db import models


class State(models.Model):
label = models.CharField(max_length=255)

def __str__(self):
return self.label


class Transition(models.Model):
source = models.ManyToManyField(State,
related_name="transition_source")
target = models.ForeignKey(State, related_name="transition_target",
on_delete=models.CASCADE)
}}}

{{{#!python
from django.contrib import admin

from .models import State, Transition


class TransitionAdmin(admin.ModelAdmin):
filter_horizontal = ['source']


admin.site.register(State)
admin.site.register(Transition, TransitionAdmin)
}}}

Would you like to prepare a patch?

--
Ticket URL: <https://code.djangoproject.com/ticket/34789#comment:4>

Reply all
Reply to author
Forward
0 new messages