#33813: Incorrect querysets for InlineModels for django.cotrib.admin
-------------------------------------+-------------------------------------
Reporter: Hristo | Owner: nobody
Trendafilov |
Type: Bug | Status: new
Component: | Version:
contrib.admin | Keywords:
Severity: Normal | admin,inlines,custom model manager
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Hello.
I have run into the following that is applicable to all Django versions.
Let's have two models and one is using a custom model manager like so
{{{
class ReviewsModelManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
qs = qs.filter(published=True)
return qs
def get_full_queryset(self):
qs = super().get_queryset()
return qs
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
objects = BaseModelManager()
class BookReview(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE,
related_name='reviews')
content = models.CharField(max_length=255)
published = models.BooleanField(default=False)
objects = ReviewsModelManager()
}}}
The concept is that we are having one book that could have multiple
reviews. A review could be published or not. We then apply a model manager
to show only published book reviews. We keep the original queryset to use
in the admin later in the `get_full_queryset`
Then we add a model admin in admin.py like so:
{{{
class ReviewTabularInline(admin.TabularInline):
def get_queryset(self, request):
qs = self.model._default_manager.get_full_queryset()
ordering = self.get_ordering(request)
if ordering:
qs = qs.order_by(*ordering)
return qs
class BookAdmin(admin.ModelAdmin):
inlines = [ReviewTabularInline]
def get_queryset(self, request):
qs = self.model._default_manager.get_full_queryset()
ordering = self.get_ordering(request)
if ordering:
qs = qs.order_by(*ordering)
return qs
}}}
Default querysets are hijacked in both admin and inline in order to
include all reviews - both published and not.
If you go to the `book admin`, the inline will display all reviews as it
should.
If you try to mark a review from `published` to `not published` in the
inline this will also work.
But if you try to mark `not-published` to `published` that is failing
with an unspecified error.
The reason for this is that the inline form does not validate.
Validation fails because the inline form receives an extra field /called
`id` by default or whatever the PK name for the model is/
That field is a `ModelChoiceField`.
But the queryset for that `ModelChoiceField` is done with the
`get_queryset` of the custom model manager - `ReviewsModelManager` that
will not include items that are not marked as `not-published`. Since you
are trying to update `non-published` to `published`, that object is going
to be missing in `ModelChoiceField` queryset which causes the field not to
validate and that drops the whole form.
This inconsistency. `ModelChoiceField` `id` field should also get the
queryset that is specified in the inline's `get_queryset`
--
Ticket URL: <https://code.djangoproject.com/ticket/33813>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/01070181aec393de-2a9f1c9f-908a-464b-a99e-aced7436a55c-000000%40eu-central-1.amazonses.com.