Open MiltonLn opened 8 years ago
@MiltonLn It looks that you are right. Filtering by multiple queryset can return duplicate objects without using distinct().
I'm curious as to how common needing .distinct()
is. We can either include an option for adding .distinct()
to the queryset ("small hammer" approach) or we can add an option to call a user-defined function that takes the filtered queryset (and a bunch of context variables) and returns a queryset ("big hammer" approach).
Initially it can be a "small hammer" approach and it's kinda easy to do, the final result can be something like:
Sometimes in Django you can't use distinct without use order_by, so it can be:
I guess it can be very common, if you take a model with a many to many field and you do .filter(thatfield__anotherfield='something') it can take duplicated results if various 'thatfield' correspond to the query, let me know if i'm wrong with the queryset use.
Thanks
Just FYI: you don't have to post images of code. You can use GitHub Flavored Markdown - you can even tell GitHub to do syntax highlighting for you!
@blag thank you :)
Hmmm, that's a good point. I'm leaning more towards the big hammer approach then. Something like this:
def filter_books(queryset, *args, **kwargs):
return queryset.order_by("id").distinct()
class Book(models.Model):
publication = models.ForeignKey(Publication)
writer = ChainedManyToManyField(
Writer,
chained_field="publication",
chained_model_field="publications",
queryset_func=filter_books,
)
That would also enable #39.
Can you think of any downside to that approach?
@blag What do you think of implementing it as a custom manager and passing his name the same way you did on the previous example?
That...is probably a better solution. 👍
This is already possible if you use the smart_selects.form_fields.ChainedModelChoiceField
and smart_selects.form_fields.ChainedManyToManyField
directly.
My custom-manager
branch should allow you to do this. You should simply specify the name of the custom manager as the named parameter manager
to smart_selects.db_fields.ChainedManyToManyField
and smart_selects.db_fields.ChainedForeignKey
. Can you test it out for me and see if it works for you?
Yes @blag just give me a couple of days and i'll test it with pleasure.
Yes, much needed this feature. For now workaround
class CustomChainedManyToManyField(ChainedManyToManyField):
manager = None
def __init__(self, *args, **kwargs):
self.manager = kwargs.pop('manager', None)
super(CustomChainedManyToManyField, self).__init__(*args, **kwargs)
def formfield(self, **kwargs):
defaults = {
'manager': self.manager
}
defaults.update(kwargs)
return super(CustomChainedManyToManyField, self).formfield(**defaults)
field_name = CustomChainedManyToManyField(Model, blank=True,
chained_field='<>',
chained_model_field='<>',
manager='chained_manager'
)
class ChainedQuerySet(models.QuerySet):
def filter(self, *args, **kwargs):
# distinct becausen we need to return only non repeated options
return super(ChainedQuerySet, self).filter(*args, **kwargs).distinct()
objects = models.Manager()
chained_manager = ChainedQuerySet.as_manager()
Done!
@kaushal235's example can also be extended to ChainedForeignKey field. I had to chain through a foreign key which had M2M association with through
model. I could easily filter the distinct choices with little tweak in his suggested snippet.
Hello, i have the following model:
So, when i try to filter on the form and select two options for the field 'temas' that have both shared options on the field 'evaluaciones' the options appears duplicated (And it's fine because Relational DB design).
on a normal case the solution here must be use a distinct on the queryset, but i can't see on the code neither the documentation an option for distinct on ChainedManyToMany, for debugging purposes i had tested this on the views file:
Notice the line 65 that has a .distinct() in the end, with this solution the select works fine (This is not a final solution, just for debugging purposes) so i need to know if this is a real issue, if so, how can be added the distinct solution to the code? i'm new to the repo so i need feedback, if this is already solved please notice me how to use it.
Thanks.