Skip to content

Instantly share code, notes, and snippets.

@craiglabenz
Last active May 8, 2022 15:36
Show Gist options
  • Save craiglabenz/06d455460bb21bb6562ac301eb04f365 to your computer and use it in GitHub Desktop.
Save craiglabenz/06d455460bb21bb6562ac301eb04f365 to your computer and use it in GitHub Desktop.
Demonstrates how I connect Models, Managers, and QuerySets, with explanations and open questions for improvement
from django.db import models
class MyModelManager(models.Manager):
# A few notes here:
#
# 1. I add this method for its type-hinted return type. This allows me to
# later write "MyModel.objects.for_user(user=user).some_other_queryset_method()"
# and have the linter agree with me that it will work.
# 2. Ultimately, I call `super().the_mirrored_method()` (in this case,
# obviously, `for_user`) because Django has already done the mirroring.
# Thus, it is safe to call super() -- the `for_user` method is waiting
# for me there.
# 3. You'll see an awkward `type: ignore` annotation on the return
# statement. That is terrible and I hate it, but necessary, because
# I haven't found another good way to convince MyPy (and by extension,
# Pylance) that the Manager method returns QuerySet instances. If I
# didn't need that `# type: ignore` comment, then I wouldn't need this
# whole method!
def for_user(self, user: "auth.User") -> "MyModelQuerySet":
return super().for_user(user) # type: ignore
class MyModelQuerySet(models.QuerySet):
def for_user(self, user: "auth.User") -> "MyModelQuerySet":
# Example pseudocode. Filters here vary, obviously.
return self.filter(user=user)
class MyModel(models.Model):
user = models.ForeignKey("auth.User")
# more fields
# This is my recommended way to set up a Manager. I always create my
# own Manager, even if I can't think of a reason I need it now, because
# I usually will eventually and it's nice to have already exist.
# And, setting it up this way correctly wires up the connection between
# a Manager and its QuerySet, including all the method mirroring from
# QuerySet to Manager.
objects: MyModelManager = MyModelManager.from_queryset(MyModelQuerySet)()
# With the above, in View code elsewhere, I can write this:
# MyModelManager.objects.for_user(user=request.user)
# and everyone agrees that the code will work :)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment