Opened 7 years ago
Last modified 6 years ago
#30000 closed Bug
Passing QuerySet constructed with .union() causes ModelMultipleChoiceField to return wrong values — at Initial Version
| 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
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 has to do with this.