Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PositionField on inherited class? #26

Open
pcompassion opened this issue Dec 30, 2013 · 4 comments
Open

PositionField on inherited class? #26

pcompassion opened this issue Dec 30, 2013 · 4 comments

Comments

@pcompassion
Copy link

I added positionField to one of the subclasses (multi-table inheritance)

I was unable to create a subclass instance because of the following lines (fields.py: 65)

    if not add and self.collection is not None:
        previous_instance = type(model_instance)._default_manager.get(pk=model_instance.pk)

It trys to get the instance which was not yet saved.

@jpwatts
Copy link
Owner

jpwatts commented Jan 12, 2014

Thanks for submitting the issue. I'm surprised to see you getting to this point in the code when adding a new instance. That should only happen if the value Django passes in for add when it calls the field's pre_save method is False, which it shouldn't be here.

Could you please write up a failing test so I can reproduce the problem?

@mtford90
Copy link

@jpwatts - I came across this same issue myself. I placed an example project with a test that fails here. It should work out of the box as it uses sqllite. Here is a summary:

Models:

class AbstractModel(models.Model):

    created_at = DateTimeField(default=timezone.now(), db_index=True)


class Person(AbstractModel):

    name = CharField(max_length=50)
    fave_cars = ManyToManyField('Car', through='FaveCar')


class Car(AbstractModel):

    model_name = CharField(max_length=50)


class FaveCar(AbstractModel):

    car = ForeignKey('Car')
    person = ForeignKey('Person')

    position = PositionField(collection='person')

    class Meta(object):
        unique_together = ('car', 'person')

Test:

class Test(TestCase):

    def setUp(self):
        super(Test, self).setUp()
        self.person = models.Person.objects.create(name='Bob')
        self.bmw = models.Car.objects.create(model_name='bmw')
        self.ford = models.Car.objects.create(model_name='ford')

    def test_can_create_fave_cars(self):
        models.FaveCar(car=self.bmw, person=self.person).save()
        models.FaveCar(car=self.ford, person=self.person).save()

Error:

Creating test database for alias 'default'...
E
======================================================================
ERROR: test_can_create_fave_cars (dpb.tests.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/mtford/Playground/django_positions_bug/dpb/tests.py", line 16, in test_can_create_fave_cars
    models.FaveCar(car=self.bmw, person=self.person).save()
  File "/Library/Python/2.7/site-packages/django/db/models/base.py", line 545, in save
    force_update=force_update, update_fields=update_fields)
  File "/Library/Python/2.7/site-packages/django/db/models/base.py", line 573, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/Library/Python/2.7/site-packages/django/db/models/base.py", line 632, in _save_table
    for f in non_pks]
  File "/Library/Python/2.7/site-packages/positions/fields.py", line 72, in pre_save
    previous_instance = type(model_instance)._default_manager.get(pk=model_instance.pk)
  File "/Library/Python/2.7/site-packages/django/db/models/manager.py", line 151, in get
    return self.get_queryset().get(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/django/db/models/query.py", line 307, in get
    self.model._meta.object_name)
DoesNotExist: FaveCar matching query does not exist.

----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (errors=1)
Destroying test database for alias 'default'...

@mtford90
Copy link

And here is my proposed fix for this: https://gist.github.com/mtford90/9854075. Let me know what you think.

I added a try/except around the get query:

try:
    previous_instance = type(model_instance)._default_manager.get(pk=model_instance.pk)
    for field_name in self.collection:
        field = model_instance._meta.get_field(field_name)
        current_field_value = getattr(model_instance, field.attname)
        previous_field_value = getattr(previous_instance, field.attname)
        if previous_field_value != current_field_value:
            collection_changed = True
            break
except model_instance.DoesNotExist:
    pass

@jpwatts
Copy link
Owner

jpwatts commented Apr 17, 2014

I'm sorry this has just been sitting here for so long; I haven't had any time lately to spend on this project. I'm not sure when that's going to change, but thank you for digging into the problem and giving me something to work from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants