Opened 6 years ago
Last modified 5 years ago
#30000 closed Bug
Passing QuerySet constructed with .union() causes ModelMultipleChoiceField to return wrong values — at Version 1
Reported by: | Thomas Hamann | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | queryset union |
Cc: | Prabakaran Kumaresshan | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
I have a form that displays large lists of selectable records using ModelMultipleChoiceFields. These fields need to show a predetermined list of records, obtained through some database queries performed within the Form's class init block.
The QuerySet required is constructed by reaching through a few ForeignKey relationships to retrieve the required records and then using the .union() method to assemble the QuerySet.
e.g.:
# Retrieve original record: base = BaseModel.objects.filter(source_name=source_name).first() # Get related record via ForeignKey relationship: related_record = base.related_record # related_record.other_related_things has ManyToMany relationship to another Model (one or more records). # So get them: other_related_things = related_record.other_related_things.all() # Loop through these: union_queryset = None for other_related_thing in other_related_things: # Each other_related_thing has a set of SelectableRecords associated with it, via a ForeignKey relationship from the latter model to the former one. This gets that QuerySet: other_related_thing_queryset = other_related_thing.selectablerecords_set.all() # Build union_queryset: if union_queryset is None: union_queryset = other_related_thing_queryset else: union_queryset = union_queryset_object.union(other_related_thing_queryset) # The resulting union_queryset is a unified queryset containing all of the required fields. # If only one other_related_thing exists, the result of evaluating the union_queryset QuerySet ought to be the # same as the result of evaluating SelectableRecords.objects.all()
However, when I pass the union_queryset to my ModelMultipleChoiceFields, validating the form returns all of the records contained in union_queryset instead of the records selected on the form. The form displays correctly.
The code used for this is:
self.fields['selectable_records'] = forms.ModelMultipleChoiceField(queryset=union_queryset, required=False, label='Selectable records', widget=forms.CheckboxSelectMultiple)
Do take note that the documentation for the .union() method (here) indicates there are some limits to the QuerySet returned, and I assume my problem may have to do with this. Still, it would be welcome if this were explained somewhere (should this behaviour be normal), as it is rather unexpected.