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

Fix bug where order is wrong after adding objects #56

Closed
wants to merge 1 commit into from

Conversation

appden
Copy link
Contributor

@appden appden commented Jul 23, 2015

This problem was caused by using the count of the objects in the intermediary join table as the starting sort value. This was insufficient because deleting objects would not update the sort values.

So imagine with a fresh database, you added 5 objects then deleted 3. The max sort value would be 4 (the 5th object would use the count prior to adding, hence 4), but when you add a new object, its sort value would be 2 (current count of intermediary objects), NOT 5!

This fixes that by querying for the maximum sort value in use by the source object's intermediary objects and using that as the starting sort value.

Since bulk_create() was introduced in Django 1.4 and there is a dummy atomic() implementation (that actually was not being used), there is no need to use a different implementation to create intermediary objects on Django 1.5. Also, this ensures the right database is being used for the transaction, which was not the case before.

This problem was caused by using the count of the objects in the intermediary join table as the starting sort value. This was insufficient because deleting objects would not update the sort values.

So imagine with a fresh database, you added 5 objects then deleted 3. The max sort value would be 4 (the 5th object would use the count prior to adding, hence 4), but when you add a new object, its sort value would be 2 (current count of intermediary objects), NOT 5!

This fixes that by querying for the maximum sort value in use by the source object's intermediary objects and using that as the starting sort value.

Since bulk_create() was introduced in Django 1.4 and there is a dummy atomic() implementation (that actually was not being used), there is no need to use a different implementation to create intermediary objects on Django 1.5. Also, this ensures the right database is being used for the transaction, which was not the case before.
@@ -316,31 +311,9 @@ def get_rel_to_model_and_object_name(self, klass):
to_object_name = to_model._meta.object_name
return to_model, to_object_name

def get_intermediate_model_sort_value_field_default(self, klass):
def default_sort_value(name):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you remove the callable here to create the default? What's the benefit of calculating in the _add_items method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! I'll try my best to explain... First of all, in general, calculating default values shouldn't have to hit the database. Doing so would hide away potential performance issues, and wouldn't really cooperate with Django migrations. It also could be the source of bugs if it depended on the caller knowing that it hits the database and thus ensuring it is called inside the appropriate atomic transaction.

In this case, we were using the get_default value only as a starting point for subsequent values (except in the Django 1.5 case where it was hitting the database every time). Now, you can read inline exactly how the starting point is calculated and be sure it's inside the transaction and thus "correct". Also, this important, it technically wouldn't quite work to keep this calculation inside get_default because it depends on the source object's primary key (it finds the maximum sort value the exists for that source object and increments from there).

Hope that helps to clear things up, thanks!

@gregmuellegger
Copy link
Collaborator

Hey, thanks a lot for this patch. I will review the code and post comments inline.

gregmuellegger added a commit that referenced this pull request Aug 6, 2015
@gregmuellegger
Copy link
Collaborator

Thank you for lining out your intend! It makes sense and I merged your code with commit ba6d5db. However this PR is not marked as merged as I modified the commit slightly (whitespace changes).

I just released 1.0.2 containing your fix.

@appden
Copy link
Contributor Author

appden commented Aug 6, 2015

Awesome, thanks @gregmuellegger!

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

Successfully merging this pull request may close these issues.

2 participants