Opened 10 years ago

Closed 8 years ago

#526 closed defect (duplicate)

Error when edit_inline model have unique_together constraint

Reported by: nesh <nesh [at] studioquattro [dot] co [dot] yu> Owned by: adrian
Component: Database layer (models, ORM) Version: master
Severity: major Keywords:
Cc: jeff@…, nesh@…, gary.wilson@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Example:

class Locale(meta.Model):
    """ available languages """
    locale = meta.CharField(maxlength=5, unique=True)
    encoding = meta.CharField(maxlength=50, choices=ENCODINGS, default='utf_8')
    name = meta.CharField(maxlength=200, unique=True)
    plural = meta.TextField('plural form',
                            help_text='plural form expression, see: <a href="http://www.gnu.org/software/gettext/manual/html_node/gettext_150.html" target="_blank">gettext</a>',
                            blank=True, null=True)
    nplurals = meta.PositiveSmallIntegerField('number of plural forms', blank=True, null=True)

    def __repr__(self):
        return self.name
    #

    def _manipulator_validate_plural(self, field_data, all_data):
        """ validate plurals """
        field_data = field_data.strip()
        if field_data == '':
            return ''

        if all_data['nplurals'].strip() == '':
            from django.core import validators
            raise validators.ValidationError('No nplurals is defined!')

        # try to compile plural expression
        try:
            from gettext import c2py
            c2py(field_data)
        except ValueError, err:
            from django.core import validators
            raise validators.ValidationError('Plural form expression error %s' % err)
    # _manipulator_validate_plural

    class META:
        ordering = ['locale']
        admin = meta.Admin(
            fields = (
                      (None, { 'fields': ('locale', 'encoding', 'name',),}),
                      ('Plurals', { 'fields': ('nplurals', 'plural'),}),
                      ),
            list_display = ('name', 'locale', 'encoding'),
        )
    # META
# Locale

class Message(meta.Model):
    """ messages """
    site = meta.ForeignKey(sites.Site, null=True)
    package = meta.ForeignKey(packages.Package, null=True)

    message = meta.CharField(maxlength=255)
    has_plural = meta.BooleanField(default=False)

    def __repr__(self):
        return self.message
    #

    class META:
        unique_together = (('site', 'package', 'message'),)
        admin = meta.Admin(
            fields = (
                      ('For', { 'fields': (('site', 'package'),),}),
                      (None, { 'fields': (('message', 'has_plural'),)}),
                      ),
            list_display = ('message', 'site', 'package', 'has_plural',),
            list_filter = ('site', 'has_plural',), #('site', 'package'),
           )
    # META
# Message

class Translation(meta.Model):
    """ translation of the message """
    locale = meta.ForeignKey(Locale)
    message = meta.ForeignKey(Message, edit_inline=meta.TABULAR, num_in_admin=2, num_extra_on_change=5)
    plural = meta.PositiveIntegerField(blank=True, null=True, default=None)
    text = meta.TextField(core=True)

    def _manipulator_validate_plural(self, field_data, all_data):
        """ validate plurals """
        field_data = field_data.strip()
        if field_data == '':
            return ''

        pl = int(field_data)
        locale = self.get_locale()
        message = self.get_message()

        if locale.nplurals is None:
            from django.core import validators
            raise validators.ValidationError('No plural form is defined for this locale!')

        if pl >= locale.nplurals:
            from django.core import validators
            raise validators.ValidationError('Plural form must be less than %s' % maxpl)

        if not message.has_plural:
            from django.core import validators
            raise validators.ValidationError("Message for this translation dosen't have has_plural set")
    # _manipulator_validate_plural

    def __repr__(self):
        if self.plural:
            return '%s[%d]: %s' % (self.get_locale().locale, self.plural, self.text)
        else:
            return '%s: %s' % (self.get_locale().locale, self.text)
    #

    class META:
        unique_together = (('locale', 'message', 'plural'),)
    # META

throws a exception in admin interface when I try to add new Message object.

There's been an error:

Traceback (most recent call last):

  File "/Users/nesh/devel/django/django/core/handlers/base.py", line 64, in get_response
    response = callback(request, **param_dict)

  File "/Users/nesh/devel/django/django/views/admin/main.py", line 766, in add_stage
    manipulator = mod.AddManipulator()

  File "/Users/nesh/devel/django/django/utils/functional.py", line 3, in _curried
    return args[0](*(args[1:]+moreargs), **dict(kwargs.items() + morekwargs.items()))

  File "/Users/nesh/devel/django/django/core/meta/__init__.py", line 1445, in manipulator_init
    self.fields.extend(f.get_manipulator_fields(rel_opts, self, change, name_prefix='%s.%d.' % (rel_opts.object_name.lower(), i), rel=True))

  File "/Users/nesh/devel/django/django/core/meta/fields.py", line 205, in get_manipulator_fields
    params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list)))

AttributeError: MessageManipulatorAdd instance has no attribute 'isUniquelocale_message_plural'

Attachments (3)

manipulator_test.diff (1.6 KB) - added by nesh <nesh [at] studioquattro [dot] co [dot] yu> 9 years ago.
manupulator tests
manipulator_test.2.diff (1.6 KB) - added by nesh <nesh [at] studioquattro [dot] co [dot] yu> 9 years ago.
some errors fixed
manipulator_test.3.diff (2.3 KB) - added by nesh <nesh [at] studioquattro [dot] co [dot] yu> 9 years ago.
final ;) tests -- pls, ignore previous

Download all attachments as: .zip

Change History (18)

comment:1 Changed 10 years ago by jforcier@…

I'm seeing the exact same issue (very similar Model, identical traceback) in the latest trunk checkout as of this date.

Additionally, #265 appears to address a similar issue, but its patch does not fix this specific form of the problem.

(sorry for the bolding, not trying to sound like a jerk, just needing emphasis =))

comment:2 Changed 10 years ago by anonymous

  • Cc jforcier@… added

comment:3 Changed 9 years ago by anonymous

I'm getting the same error as well using trunk as of today. 'date' is a foreign key edited inline in my model.

AttributeError at /admin/news/newslists/add/
NewsListManipulatorAdd instance has no attribute 'isUniqueurl_date'
Request Method: GET
Request URL: http://localhost:8000/admin/news/newslists/add/
Exception Type: AttributeError
Exception Value: NewsListManipulatorAdd instance has no attribute 'isUniqueurl_date'
Exception Location: /Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/django/core/meta/fields.py in get_manipulator_fields, line 255

comment:4 Changed 9 years ago by bshi@…

Hi - I found the same thing; is there a workaround?

class PhotoTag( meta.Model ):
    tid = meta.ForeignKey( Tag, core = True )
    pid = meta.ForeignKey( Photo, core = True, verbose_name = "Photo Tag", edit_inline = meta.TABULAR, num_in_admin=1, num_extra_on_change=1 )
    
    class META:
        # following prevents identical tags on photo TODO: doesn't work
        unique_together = ( ( "tid", "pid" ), )

Results in

AttributeError at /admin/photo/photos/add/
PhotoManipulatorAdd instance has no attribute 'isUniquetid_pid'

comment:5 Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

  • Cc nesh@… added
  • Component changed from Admin interface to Database wrapper
  • priority changed from normal to high
  • Severity changed from normal to major
  • Version set to SVN

I almost forgot about this one, until bites me again :(

Any solution?

comment:6 Changed 9 years ago by bitprophet

  • Cc jeff@… added; jforcier@… removed

comment:7 Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

unique_together = ( ( "tid", "pid" ), )

Strange, if you reverse order to ('pid', 'tid') then it works.

I'm trying to make test for that (in tests/modeltests/manipulators/models.py)

Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

manupulator tests

Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

some errors fixed

comment:8 Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

I investigated a little further and it seems that there are two distinct bugs.

  • You must have related field in unique_together or you will get the same error.
  • order of fields in unique_together is important (second test). If you have related field after any other field you'll get this error.

p.s. Can someone with TRAC_ADMIN delete original example?

comment:9 Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

You must have related field in unique_together or you will get the same error.

Update (and test update):

You must have filed for witch edit_inline=True in unique_together and this field must come first.

Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

final ;) tests -- pls, ignore previous

comment:10 Changed 9 years ago by nesh <nesh [at] studioquattro [dot] co [dot] yu>

  • Summary changed from Exception when using unique_together in edit_inline model to Error when edit_inline model have unique_together constraint

comment:11 Changed 9 years ago by Gary Wilson <gary.wilson@…>

  • Cc gary.wilson@… added

comment:12 Changed 9 years ago by ramiro

see also #2415, #2470

comment:13 Changed 8 years ago by Gary Wilson <gary.wilson@…>

  • Triage Stage changed from Unreviewed to Accepted

comment:14 Changed 8 years ago by Nebojša Đorđević <nesh@…>

  • Cc nesh@… added; nesh@… removed

comment:15 Changed 8 years ago by Simon G. <dev@…>

  • Resolution set to duplicate
  • Status changed from new to closed

Duplicate of #565

Note: See TracTickets for help on using tickets.
Back to Top