-
Notifications
You must be signed in to change notification settings - Fork 121
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
Filtering on the deleted field is done on evaluation. #65
Filtering on the deleted field is done on evaluation. #65
Conversation
16d92df
to
5d15cef
Compare
safedelete/managers.py
Outdated
return queryset | ||
|
||
def all_with_deleted(self): | ||
"""Deprecated because all(show_deleted=True) is meant for related managers.""" | ||
warnings.warn('deprecated', DeprecationWarning) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better if we not deprecate this, but add helper methods for all visibility modifiers. We should perhaps add a note with rst stating that this should only be used for related fields.
safedelete/managers.py
Outdated
) | ||
if hasattr(attr, '__call__') and name in evaluation_methods: | ||
def decorator(*args, **kwargs): | ||
self.filter_visibility() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be documented in the docs for when using custom QuerySets. When working with the QuerySet's query
directly that hasn't had the deleted filter applied yet, filter_visibility
needs to be called first.
5d15cef
to
df1774d
Compare
* Added docs to tox and README.
df1774d
to
38537a2
Compare
This and #64 are ready to be merged if everything looks good to you. I moved the SafeDeleteQueryset to |
Thanks a lot 👍 . If you could just add a changelog in the |
@Gagaro I don't really mind how you merge it. Might be easier to close the first one and refer to this one saying that this one is merged. But if you still want to merge both, I guess you should be fine if you don't create a merge commit. I'll add the changes to the changelog tonight. Do you want a version bump then...? |
Don't worry about the version, I'll take care of it if I release it. |
Hey guys! It seems that this code change gave me an issue, as following:
Gives me:
|
Looking at the source code:
Removing |
# visiblity set. | ||
evaluation_methods = ( | ||
'_fetch_all', 'count', 'exists', 'aggregate', 'update', '_update', | ||
'delete', 'undelete', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could first
be added here? I might have overlooked something when _fetch_all
gets called. I used _fetch_all
because it gets called in a lot of functions, but I'd have to look at it again. I think it's trying to filter the visibility after you call first
when it should filter it before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me try that right away @AndreasBackx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tried to add first
evaluation_methods, but that didn't help :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow 🎉
Looked into the code of django.models.query
and saw it hit _fetch_all
, upon looking at the method it looks like this:
def _fetch_all(self):
if self._result_cache is None:
self._result_cache = list(self.iterator())
if self._prefetch_related_lookups and not self._prefetch_done:
self._prefetch_related_objects()
So, fetching all if cached just by the pervious iterator, otherwise prefetch related objects. Prefetching usually means that it's a sliced queryset (correct me if I'm wrong). Changing the evaluation_methods
_fetch_all
to _prefetch_related_objects
worked for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait that didn't do it, but there is something else that happened. Our UserManager
is extending get_queryset
to add some prefetch_related
and select_related
, removing that together with removing _fetch_all
replacing it with _prefetch_related_objects
works.
Is there a way around that issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please create a PR with a test case that clearly shows your problem. We can work on the PR and fix the problem without breaking any of the other tests.
@glemmaPaul could you perhaps make a PR with a test that fails? |
See #64 for extra information (this PR is branched from #64), but here's a summary:
SafeDeleteMixin.refresh_from_db
works if visibility is set toDELETED_VISIBLE_BY_FIELD
.SafeDeleteMixin.objects.filter(pk={pk}).get()
does not give aDoesNotExist
if visibility is set toDELETED_VISIBLE_BY_FIELD
. This is whyrefresh_from_db
works now. If you have any idea on how to make this work for the other ones, feel free to leave some feedback. I cannot come up with a good solution as they would have race conditions.SafeDeleteMixin.objects.select_related('something').get(pk={pk})
would ignore theselect_related
becauseget
would create a new queryset. It apparently didn't in my initial tests which still boggles me. Anyhow, added tests assures it doesn't now.SafeDeleteQueryset
.So the
filter(deleted__isnull=True/False)
is added when the QuerySet is evaluated. See__getattribute__
which intercepts those calls to add it. Would love some feedback, the added code has got documentation so check those too.