On this line: "if row_data in seen_data:", because row_data contains a
list and seen_data is a set (row_data: (1, [1, 1]) / seen_data: set())
Example to reproduce:
models:
{{{#!python
class Map(models.Model):
name = models.CharField(_('name'), max_length=128)
class MapSpot(models.Model):
map = models.ForeignKey('body.Map', related_name='spots')
position = ArrayField(models.IntegerField(), size=2)
class Meta:
unique_together = [('map', 'position')]
}}}
admin:
{{{#!python
class MapSpotInline(admin.TabularInline):
model = MapSpot
extra = 0
@admin.register(Map)
class MapAdmin(admin.ModelAdmin):
inlines = [MapSpotInline]
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26819>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* needs_better_patch: => 0
* component: Uncategorized => contrib.postgres
* needs_tests: => 0
* needs_docs: => 0
* type: Uncategorized => Bug
* stage: Unreviewed => Accepted
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:1>
* owner: nobody => PREM1980
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:2>
Comment (by PREM1980):
Im trying to recreate this issue but have issues.
{{{
class Map(models.Model):
name = models.CharField(_('name'), max_length=128)
class MapSpot(models.Model):
map = models.ForeignKey('body.Map', related_name='spots')
position = ArrayField(models.IntegerField(), size=2)
class Meta:
unique_together = [('map', 'position')]
}}}
Error:-
File "/Users/prem/Documents/django-contribute/mysite/polls/models.py",
line 13, in Map
name = models.CharField(_('name'), max_length=128)
NameError: name '_' is not defined
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:3>
Comment (by gleber-diniz):
Replying to [comment:3 PREM1980]:
> Im trying to recreate this issue but have issues. Please provide any
additional information that you have.
>
> File "/Users/prem/Documents/django-contribute/mysite/polls/models.py",
line 13, in Map
> name = models.CharField(_('name'), max_length=128)
> NameError: name '_' is not defined
use:
from django.utils.translation import ugettext_lazy as _
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:4>
Comment (by PREM1980):
(djangodev) prem-MBP:mysite premlaks$ python manage.py migrate
SystemCheckError: System check identified some issues:
{{{
ERRORS:
<class 'polls.admin.MapSpotInline'>: (admin.E202) 'polls.MapSpot' has no
ForeignKey to 'polls.Map'.
polls.MapSpot.map: (fields.E300) Field defines a relation with model
'body.Map', which is either not installed, or is abstract.
polls.MapSpot.map: (fields.E307) The field polls.MapSpot.map was declared
with a lazy reference to 'body.map', but app 'body' isn't installed.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:5>
Comment (by gleber-diniz):
Replying to [comment:5 PREM1980]:
> (djangodev) prem-MBP:mysite premlaks$ python manage.py migrate
> SystemCheckError: System check identified some issues:
>
>
> {{{
> ERRORS:
> <class 'polls.admin.MapSpotInline'>: (admin.E202) 'polls.MapSpot' has no
ForeignKey to 'polls.Map'.
> polls.MapSpot.map: (fields.E300) Field defines a relation with model
'body.Map', which is either not installed, or is abstract.
> polls.MapSpot.map: (fields.E307) The field polls.MapSpot.map was
declared with a lazy reference to 'body.map', but app 'body' isn't
installed.
> }}}
You have to replace 'body.Map' with the app name you are using
('polls.Map' apparently)
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:6>
Comment (by PREM1980):
Thanks. That worked.
I was able to build the models, now when I try logging to my admin it
throws this error.
Not sure if you had the same problem.
{{{
ProgrammingError at /admin/polls/map/
relation "polls_map" does not exist
LINE 1: SELECT COUNT(*) AS "__count" FROM "polls_map"
^
Request Method: GET
Request URL: http://localhost:8000/admin/polls/map/
Django Version: 1.11.dev20160628202456
Exception Type: ProgrammingError
Exception Value:
relation "polls_map" does not exist
LINE 1: SELECT COUNT(*) AS "__count" FROM "polls_map"
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:7>
Comment (by gleber-diniz):
Replying to [comment:7 PREM1980]:
> Thanks. That worked.
> I was able to build the models, now when I try logging to my admin it
throws this error.
> Not sure if you had the same problem.
>
>
> {{{
> ProgrammingError at /admin/polls/map/
> relation "polls_map" does not exist
> LINE 1: SELECT COUNT(*) AS "__count" FROM "polls_map"
> ^
> Request Method: GET
> Request URL: http://localhost:8000/admin/polls/map/
> Django Version: 1.11.dev20160628202456
> Exception Type: ProgrammingError
> Exception Value:
> relation "polls_map" does not exist
> LINE 1: SELECT COUNT(*) AS "__count" FROM "polls_map"
> }}}
You need to run migrate command to create database tables
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:8>
Comment (by PREM1980):
This issue occurs as the array item is stored in the lists and there is a
mis-match while comparison.
The arrayitem is stored in row_data as list and list are not hashable as
the error says.
if row_data in seen_data:
This issue can be fixed by changing this line ie; return a tuple instead
of list.
https://github.com/PREM1980/django/blob/master/django/contrib/postgres/forms/array.py#L56
Please review and provide your comments.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:9>
Comment (by timgraham):
Not sure without looking into the details myself, but it might be better
if the `validate_unique()` method took care of casting as needed since
changing the return value of `to_python()` could be backwards-
incompatible.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:10>
Old description:
> It happens on a second save (when there is already data to be validated)
>
> On this line: "if row_data in seen_data:", because row_data contains a
> list and seen_data is a set (row_data: (1, [1, 1]) / seen_data: set())
>
> Example to reproduce:
>
> models:
> {{{#!python
> class Map(models.Model):
> name = models.CharField(_('name'), max_length=128)
>
> class MapSpot(models.Model):
> map = models.ForeignKey('body.Map', related_name='spots')
> position = ArrayField(models.IntegerField(), size=2)
>
> class Meta:
> unique_together = [('map', 'position')]
> }}}
>
> admin:
> {{{#!python
> class MapSpotInline(admin.TabularInline):
> model = MapSpot
> extra = 0
>
> @admin.register(Map)
> class MapAdmin(admin.ModelAdmin):
> inlines = [MapSpotInline]
> }}}
New description:
--
Comment (by PREM1980):
As you mentioned, implemented fix in validate_unique() method. The above
code fixes the issue and all the unit tests got passed.
The only problem is Im not sure how to write the test case. It needs to be
simulated as if a user creates a form in the html page. Do you have any
pointers for testing similar condition?
row_data = tuple(d._get_pk_val() if hasattr(d, '_get_pk_val') else
tuple(d)
if type(d) is list else d for d in
row_data)
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:11>
Comment (by timgraham):
Take a look at `tests/postgres_tests/test_array.py` for the existing tests
for `ArrayField`.
By the way, you inadvertently deleted the ticket's description in your
last comment. Can you restore it? Deleting your comment should undo that
action if you can't find another way.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:12>
Comment (by PREM1980):
Sorry about that..But Im unable to delete my comment. If you have access,
pls go ahead and delete it.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:13>
Old description:
New description:
It happens on a second save (when there is already data to be validated)
On this line: "if row_data in seen_data:", because row_data contains a
list and seen_data is a set (row_data: (1, [1, 1]) / seen_data: set())
Example to reproduce:
models:
{{{#!python
class Map(models.Model):
name = models.CharField(_('name'), max_length=128)
class MapSpot(models.Model):
map = models.ForeignKey('body.Map', related_name='spots')
position = ArrayField(models.IntegerField(), size=2)
class Meta:
unique_together = [('map', 'position')]
}}}
admin:
{{{#!python
class MapSpotInline(admin.TabularInline):
model = MapSpot
extra = 0
@admin.register(Map)
class MapAdmin(admin.ModelAdmin):
inlines = [MapSpotInline]
}}}
--
Comment (by claudep):
Description restored.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:14>
Comment (by Meiyer):
This happens only for Inline admin models (only `validate_unique()` of
`BaseModelFormSet` contains the problematic code).
This is not limited to `ArrayField`; any custom field may be affected. In
our case, the `phonenumber_field.modelfields.PhoneNumberField` is causing
the error `unhashable type: 'PhoneNumber'`. Since Django documentation
does not mandate that custom fields are hashable (i.e., define the
`__hash__()` method), I suppose that most of the existing non-builtin
fields are affected.
Looks like the solution is either to keep `seen_data` as a `set()` and
rely on some property of the field (unreliable and error-prone, see sample
code below), or give up `set()` and manually implement removal of
duplicates.
{{{
row_data = tuple(d._get_pk_val() if hasattr(d, '_get_pk_val') else
d if d.__hash__ is not None else
d.__repr__()
for d in row_data)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:15>
* component: contrib.postgres => contrib.admin
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:16>
* component: contrib.admin => Forms
Old description:
> It happens on a second save (when there is already data to be validated)
>
> On this line: "if row_data in seen_data:", because row_data contains a
> list and seen_data is a set (row_data: (1, [1, 1]) / seen_data: set())
>
> Example to reproduce:
>
> models:
> {{{#!python
> class Map(models.Model):
> name = models.CharField(_('name'), max_length=128)
>
> class MapSpot(models.Model):
> map = models.ForeignKey('body.Map', related_name='spots')
> position = ArrayField(models.IntegerField(), size=2)
>
> class Meta:
> unique_together = [('map', 'position')]
> }}}
>
> admin:
> {{{#!python
> class MapSpotInline(admin.TabularInline):
> model = MapSpot
> extra = 0
>
> @admin.register(Map)
> class MapAdmin(admin.ModelAdmin):
> inlines = [MapSpotInline]
> }}}
New description:
It happens on a second save (when there is already data to be validated)
On this line: "if row_data in seen_data:", because row_data contains a
list and seen_data is a set (row_data: (1, [1, 1]) / seen_data: set())
Example to reproduce:
models:
{{{#!python
class Map(models.Model):
name = models.CharField('name', max_length=128)
class MapSpot(models.Model):
map = models.ForeignKey('body.Map', related_name='spots')
position = ArrayField(models.IntegerField(), size=2)
class Meta:
unique_together = [('map', 'position')]
}}}
admin:
{{{#!python
class MapSpotInline(admin.TabularInline):
model = MapSpot
extra = 0
@admin.register(Map)
class MapAdmin(admin.ModelAdmin):
inlines = [MapSpotInline]
}}}
--
Comment:
I believe it affects all inline formsets, not just those in the admin.
There's a [https://github.com/django/django/pull/7094 PR] without tests.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:17>
* owner: PREMANAND => felixxm
* version: 1.9 => master
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:18>
* owner: felixxm => (none)
* status: assigned => new
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:19>
* status: new => assigned
* owner: (none) => Demur Nodia
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:20>
Comment (by Demur Nodia):
Prepared fix for the issue during DjangoCon Europe 2018 sprints
PR: https://github.com/django/django/pull/9993
Used suggestions from previous work:
* https://github.com/django/django/pull/7094#issuecomment-251481149
* https://github.com/django/django/pull/7094#issuecomment-239900389
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:21>
* has_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:22>
* needs_better_patch: 0 => 1
Comment:
Patch looks good; there were just a few adjustments needed (Review on PR).
Please uncheck Patch needs improvement when they're addressed and we'll
get this in.
Thanks Demur!
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:23>
* needs_better_patch: 1 => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:24>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"06a11ef6ecf324db0a1530b8cca727883698f442" 06a11ef]:
{{{
#!CommitTicketReference repository=""
revision="06a11ef6ecf324db0a1530b8cca727883698f442"
Fixed #26819 -- Fixed BaseModelFormSet.validate_unique() "unhashable type:
list" crash.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:25>
Comment (by ivirabyan):
Although this has been fixed specifically for ArrayField, we still get
this error with JSONField. Probably more generic solution needed.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:26>
Comment (by Carlton Gibson):
Ivan, please open a new ticket with the minimal reproduce example. Thanks.
--
Ticket URL: <https://code.djangoproject.com/ticket/26819#comment:27>