[Django] #30260: ManyToManyField with a non-list default value has different behavior in an inlined Admin vs a standalone Admin

3 views
Skip to first unread message

Django

unread,
Mar 17, 2019, 9:09:05 AM3/17/19
to django-...@googlegroups.com
#30260: ManyToManyField with a non-list default value has different behavior in an
inlined Admin vs a standalone Admin
-------------------------------------+-------------------------------------
Reporter: Landcross | Owner: nobody
Type: Bug | Status: new
Component: | Version: 2.1
Uncategorized | Keywords: ManyToManyField,
Severity: Normal | Inline, Admin
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
First off, I'm new to this bug-tracker and I'm by no means a Django
expert, I just use Django casually in my free time. So, I'm sorry if this
doesn't belong in the bug tracker. Anyway, on to the problem I
encountered.

In short: there seems to be a different behavior for a ManyToManyField
with a non-list (integer) default value when it's in an Admin Inline vs
when it's in its own Admin page. In fact, in an Inline Django crashes on
save whereas on a non-inline it saves just fine.

I encountered this problem in a personal project and to check this problem
I made a small test-project to test it and also help explain the problem.

Consider the following model.py:

{{{
from django.db import models


class Author(models.Model):
name = models.CharField(max_length=255)

def __str__(self):
return self.name


class Series(models.Model):
name = models.CharField(max_length=255)

def __str__(self):
return self.name


class Book(models.Model):
title = models.CharField(max_length=255)
series = models.ForeignKey(to=Series, on_delete=models.CASCADE)
author = models.ManyToManyField(to=Author, default=3)

def __str__(self):
return self.title
}}}

And the following admin.py:

{{{
from django.contrib import admin

from stack.models import Book, Series, Author


class BookInline(admin.StackedInline):
model = Book
extra = 0


class SeriesAdmin(admin.ModelAdmin):
inlines = [
BookInline
]


admin.site.register(Book)
admin.site.register(Series, SeriesAdmin)
admin.site.register(Author)
}}}

(Note: the above example assumes you have at least 3 authors already
created in the database to work properly).

Now if I were to run the above application and go to the Book admin page
and create a new Book, the default value of Author works fine; the 3rd
author is visibly selected and on saving it gets saved no problem
whatsoever. However... If I were to go the the Series admin page (which
has a Book inline) and create a new Series, the Author field seems to work
just fine; the 3rd Author is selected. But, on save it crashes with the
following error:

> object of type 'int' has no len()

Which originates from django\forms\models.py in has_changed, line 1351.

And it doesn't matter whether I manually select another Author, the save
always crashes (unless I don't any any Book/Inline to the Series object).
Not that editing and saving a Series object with already existing Book
inlines works fine (unless I try to add a new Book to the Series).

The solution to the crash is simple. Instead of default=3 on the Book
model, we can change it to default=[3] and everything works like a charm.

Now, I don't know if a non-list default value for a ManyToManyField is
something that should be possible or is actually something that should not
be possible, but happens to work in some cases nonetheless. However, I do
think the difference in behavior between the non-inline and the inline
should be the same, whether that is a crash or a functioning save.

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

Django

unread,
Mar 21, 2019, 6:25:41 AM3/21/19
to django-...@googlegroups.com
#30260: ManyToManyField with a non-list default value has different behavior in an
inlined Admin vs a standalone Admin
-------------------------------------+-------------------------------------
Reporter: Merlijn | Owner: nobody
Type: Bug | Status: closed
Component: Uncategorized | Version: 2.1
Severity: Normal | Resolution: invalid
Keywords: ManyToManyField, | Triage Stage:
Inline, Admin | Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Carlton Gibson):

* status: new => closed
* resolution: => invalid


Comment:

Hi. Thanks for the report.

> Instead of default=3 on the Book model, we can change it to default=[3]
and everything works like a charm.

You've hit the nail on the head here. A scalar value doesn't make sense as
the default for a `ManyToManyField`.

**Possibly** we could add some kind of check that default values had
sensible values, but it's not at all clear that would be worth the effort,
we're in a dynamic language so this kind of thing can happen and, short of
a concrete suggestion this isn't really actionable as is.

As such I'm going to close this. I hope that makes sense.

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

Django

unread,
Mar 21, 2019, 9:57:42 AM3/21/19
to django-...@googlegroups.com
#30260: ManyToManyField with a non-list default value has different behavior in an
inlined Admin vs a standalone Admin
-------------------------------------+-------------------------------------
Reporter: Merlijn | Owner: nobody
Type: Bug | Status: closed
Component: contrib.admin | Version: 2.1

Severity: Normal | Resolution: invalid
Keywords: ManyToManyField, | Triage Stage:
Inline, Admin | Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

* component: Uncategorized => contrib.admin


Comment:

See also #2750 which aims to clarify how a `default` works for
`ManyToManyField`.

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

Reply all
Reply to author
Forward
0 new messages