Today's little snippet: Filtering a loosely coupled many-to-many relationship. As revealed earlier, I don't really "get" the difficulty with many-to-many relationships. I don't even get the difficulty with signals; if you define the many-to-many manually, handling signals on it is trivial compared to trying to do it manually in one of the referring classes.
Today, I was working on an issues tracker. There are two classes at work here, the Profile and the Issue. One profile may be interested in many Issues, and obviously one Issue may be of interest to many Profiles.
This calls for a ProfileIssue table that stands independent (in my development paradigm) of both Profiles and Issues. As I was working on a dashboard, I realized that one of the things I wanted was not just a list of the issues the profile was following, but also a list of the issues that the profile was responsible for creating. As it turned out, adding that query to the ProfileIssueManager is trivial, but requires a little knowledge:
class ProfileIssueManager(models.Manager):
def from_me(self, *args, **kwargs):
return self.filter(issue__creator__id = self.core_filters['profile__id'])
The secret here in knowing about the core_filters attribute in the RelatedManager. It contains the remote relationship key that you can use; calling from_me from profiles works, but calling it from anywhere else doesn't. The IssueRelatedManager won't have a profile_id and this will blow up. That's okay; using it that way is an error, and this is a strong example of Crash Early, Crash Often.
I can here some of you cry, "Now why, why would you need such a thing?" Well, the answer is pretty simple: templates. Having one of these allows me to write:
<p>Issues tracked: {{ profile.issues.count }}</p>
<p>Issues created: {{ profile.issues.from_me.count }}</p>
And everything will work correctly.