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: migrate drop the wrong m2m field when model have multi m2m fields #376

Closed
wants to merge 7 commits into from

Conversation

waketzheng
Copy link
Contributor

@waketzheng waketzheng commented Dec 5, 2024

Fixes #375
Fixes #150

Description

The two bugs are some thing like the following case:

old = [{'through': 'a'}, {'through': 'b'}, {'through': 'c'}]
new = [{'through': 'a'}, {'through': 'c'}]
print(list(dictdiffer.diff(old, new)))

Got:

[('change', [1, 'through'], ('b', 'c')),
 ('remove', '', [(2, {'through': 'c'})])]

Expected:

[('remove', '', [(1, {'through': 'b'})])]

Reason

When use dictdiffer.diff to compare two lists of dicts, it just compare elements at the same position:

old[0] vs new[0]
old[1] vs new[1]

Solution

  • 1. use a custom diff function that generate the expected output:
def diff(old: dict, new: dict, key: str) -> list[tuple]:
      # compare dicts that with same key instead of compare dicts with same index
  • 2. reorder the list elements: in this case switch old[1] and old[2] will get the expected output

@waketzheng waketzheng requested a review from henadzit December 5, 2024 15:56
Copy link
Contributor

@henadzit henadzit left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! I left a few comments.

aerich/utils.py Show resolved Hide resolved
aerich/utils.py Show resolved Hide resolved
old_m2m_fields: list[dict], new_m2m_fields: list[dict]
) -> tuple[list[dict], list[dict]]:
"""
Reorder m2m fields to help dictdiffer.diff generate more precise changes
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please explain why we need to order the fields in this way? Is the code that follows this expects some sort of ordering? What are the criteria for this ordering?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. why we need to order the fields in this way?
    Good question~
    May be a custom diff function is a better solution:
-                if old_m2m_fields and new_m2m_fields:
-                    old_m2m_fields, new_m2m_fields = reorder_m2m_fields(
-                        old_m2m_fields, new_m2m_fields
-                    )
-                for action, option, change in diff(old_m2m_fields, new_m2m_fields):
+                for action, option, change in diff_plus(old_m2m_fields, new_m2m_fields):
  1. Is the code that follows this expects some sort of ordering? What are the criteria for this ordering?
    All cases are covered by unittest: https://github.com/tortoise/aerich/pull/376/files#diff-33c13e0b177bacd2f02e29bcb8aea5b49e7ce34901fd8f41fefb65defba1bd33R7

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the reply!

I'm not saying that a custom diff function is better, I'm just trying to understand why this ordering is required. if it's really hard to explain with a spoken language, it's a good sign that something isn't right.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@henadzit I updated the PR description

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@henadzit I updated the PR description

@henadzit Thanks for you comments. I created a new PR, which fix the issue by another solution: #390

@waketzheng waketzheng closed this Dec 16, 2024
@waketzheng waketzheng deleted the fix-m2m-remove branch December 16, 2024 17:45
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.

Migrate drop the wrong m2m field when model have multi m2m fields Add ManyToManyField will break migrate
2 participants