Django自定义Manager重命名字段后,get与filter为何表现不同?
.filter() work with my renamed field but .get() doesn't? Great question! Let's break down exactly what's happening here with your custom Manager and the key differences between how Django handles filter() and get() when working with aliased fields.
First, a quick recap of your setup: you’ve overridden get_queryset() to return a ValuesQuerySet that renames original_field to renamed_field using an F() expression.
The Root Cause
The issue boils down to two things: how Django resolves aliased fields in query conditions and a fundamental SQL execution rule:
When you use
Model.objects.filter(renamed_field='Test'):- Django recognizes that
renamed_fieldis defined as a reference tooriginal_fieldvia theF()expression in yourvalues()call. It smartly resolves the alias back to the actual database field, generating SQL that looks like this:SELECT original_field AS renamed_field FROM your_model WHERE original_field = 'Test'; - This works because the filter condition targets the real database field (
original_field), which is valid in theWHEREclause.
- Django recognizes that
When you use
Model.objects.get(renamed_field='Test'):- Django’s
get()method doesn’t handle the alias resolution the same way. Instead, it tries to userenamed_fielddirectly in theWHEREclause, producing SQL like this:SELECT original_field AS renamed_field FROM your_model WHERE renamed_field = 'Test'; - SQL doesn’t allow using SELECT aliases in the WHERE clause (since WHERE runs before SELECT, the alias doesn’t exist yet). This query returns no matching rows, hence the
DoesNotExisterror.
- Django’s
Fixes to Try
Here are a few straightforward solutions depending on your needs:
Option 1: Use the original field in get() (quick fix)
Since get() can’t resolve the alias, you can explicitly reference the original field name:
Model.objects.get(original_field='Test')
Option 2: Switch to annotate() instead of values() (cleanest long-term fix)
If you want the renamed field to work across all query methods (including get()), replace values() with annotate(). This adds renamed_field as an annotation to your model instances, so Django can properly resolve it in any query:
class CustomManager(models.Manager): def get_queryset(self): return super().get_queryset().annotate(renamed_field=F('original_field'))
Now both filter() and get() will work seamlessly with renamed_field.
Option 3: Manually resolve the alias in get()
If you need to stick with values(), you can use the F() expression directly in your get() condition to target the original field:
Model.objects.get(F('original_field')='Test')
内容的提问来源于stack exchange,提问作者Joshua

