Opened 18 years ago

Closed 17 years ago

#1281 closed defect (invalid)

Options.get_field() fails to check one_to_one_field, causes bogus validation error

Reported by: python@… Owned by: Adrian Holovaty
Component: Metasystem Version: 0.91
Severity: normal Keywords: FieldDoesNotExist Options get_field to_field
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I have a simple model which described 4 different bugs, one of which has a ticket with patch.
I have a patch for the last bug (labeled 'Bug3') which this ticket is for. I will file the others once I get a chance.
The problem is that Options objects which are constructed from Model classes which inherit from other Model classes may have a 'one_to_one_field' which is not in its 'fields' attribute. This can cause a bogus app validation error

meta_bug.py

from django.core import meta

# Create your models here.
class A(meta.Model):
    name = meta.SlugField(blank=False, unique=True)
    class META:
        admin = meta.Admin()
    def __repr__(self):
        return self.name

class B(meta.Model):
    a = meta.OneToOneField(A)
    ## Bug1: NEED to add another Field or Admin B edits will crash!
    class META:
        order_with_respect_to = 'a' # Ticket #930 (defect) workaround
        admin = meta.Admin()
    def __repr__(self):
        return "B - " + repr(self.get_a())

class C(meta.Model):
    b = meta.ForeignKey(B,edit_inline=meta.TABULAR,
                        to_field='a_id') # Bug2: to_field defaults to 'a' which
                                         # is wrong and causes Admin B Add's
                                         # to fail.
    data = meta.SlugField(core=True)
    def __repr__(self):
        return self.data

class _B(meta.Model):
    ap = meta.OneToOneField(A)
    class META:
        order_with_respect_to = 'a' # Ticket #930 (defect) workaround

class BP(_B):
    something = meta.SlugField() ## prevent Bug1 to show Bug3...

class CP(meta.Model):
    bp = meta.ForeignKey(BP,edit_inline=meta.TABULAR,
                         to_field='ap_id') # Bug3: Bug2 workaround no longer
                                           # works due to early model validation
                                           # error... Patch included.
    data = meta.SlugField(core=True)
    def __repr__(self):
        return self.data

This gives the following validation error:

Mya@miyu /c/django/projects/pycon
$ python manage.py install meta_bug
Traceback (most recent call last):
  File "manage.py", line 11, in ?
    execute_manager(settings)
  File "c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/management.py", line 990, in execute_manager
    execute_from_command_line(action_mapping)
  File "c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/management.py", line 965, in execute_from_command_line
    output = action_mapping[action](mod)
  File "c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/management.py", line 405, in install
    sql_list = get_sql_all(mod)
  File "c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/management.py", line 268, in get_sql_all
    return get_sql_create(mod) + get_sql_initial_data(mod)
  File "c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/management.py", line 70, in get_sql_create
    rel_field = f.rel.get_related_field()
  File "c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/meta/fields.py", line 846, in get_related_field
    return self.to.get_field(self.field_name)
  File "c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/meta/__init__.py", line 463, in get_field
    raise FieldDoesNotExist, "name=%s" % name
django.core.meta.FieldDoesNotExist: name=a_id

Here is a patch which fixes this bug:

  • django

    old new  
    460460        for f in to_search:
    461461            if f.name == name:
    462462                return f
     463        if (hasattr(self, 'one_to_one_field') and
     464            self.one_to_one_field is not None and
     465            self.one_to_one_field.name == name):
     466            return self.one_to_one_field
    463467        raise FieldDoesNotExist, "name=%s" % name
    464468
    465469    def get_order_sql(self, table_prefix=''):

Attachments (2)

1281_patch.diff (773 bytes ) - added by python@… 18 years ago.
patch (same as diff in description)
1281_patch2.diff (1.6 KB ) - added by python@… 18 years ago.
updated patch fixing more…

Download all attachments as: .zip

Change History (4)

by python@…, 18 years ago

Attachment: 1281_patch.diff added

patch (same as diff in description)

comment:1 by python@…, 18 years ago

The problem is more protracted than I discribed, and the patch alone is not enough to fix the problem.
This will fix some validation issues, but not a real install (i.e. the error above still exists).
The end problem is that in the admin interface, if the to_field does not have the '_id' form then add and edit operations fail.
In the end its not the to_field which is 100% the problem. another patch to a lower in init.py is needed to deal with the
name resolution for OneToOne fields. This is Bug2 listed above.

The two can not be fixed in isolation and are related.

Here is the new diff:

  • c:/python24/lib/site-packages/django-0.91-py2.4.egg/django/core/meta/__init__.py

     
    460460        for f in to_search:
    461461            if f.name == name:
    462462                return f
     463        if (hasattr(self, 'one_to_one_field') and
     464            self.one_to_one_field is not None and
     465            self.one_to_one_field.name == name):
     466            return self.one_to_one_field
    463467        raise FieldDoesNotExist, "name=%s" % name
    464468
    465469    def get_order_sql(self, table_prefix=''):
     
    18431847                    # case, because they'll be dealt with later.
    18441848
    18451849                    if f == related.field:
    1846                         param = getattr(new_object, related.field.rel.field_name)
     1850                        to = related.field.rel.to
     1851                        if (hasattr(to, 'one_to_one_field') and
     1852                            to.one_to_one_field and
     1853                            to.one_to_one_field.name == related.field.rel.field_name):
     1854                            param = getattr(new_object, related.field.rel.field_name + '_id')
     1855                        else:
     1856                            param = getattr(new_object, related.field.rel.field_name)
    18471857                    elif add and isinstance(f, AutoField):
    18481858                        param = None
    18491859                    elif change and (isinstance(f, FileField) or not child_follow.get(f.name, None)):

by python@…, 18 years ago

Attachment: 1281_patch2.diff added

updated patch fixing more...

comment:2 by Chris Beaven, 17 years ago

Resolution: invalid
Status: newclosed

This is pretty old, pre-magic removal, and no one has commented it's still a problem.

If anyone is having this issue still, feel free to reopen.

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