1👍
class Channel(models.Model):
created_date = models.DateTimeField(auto_now_add=True)
channel_title = models.CharField(max_length=50, unique=True)
channel_description = models.CharField(max_length=100)
channel_creator = models.ForeignKey(User)
channel_private = models.BooleanField(default=False)
channel_users = models.ManyToManyField(User, through='Membership', related_name='channels', blank=True)
channel_posts = models.ManyToManyField(Post, related_name='channel_post', blank=True)
initial_invites = models.ForeignKey(User, null=True, blank=True, related_name='initial_invites')
objects = models.Manager()
@property
def active_posts(self):
return self.channel_posts.filter(deleted=None)
Very simple, just added an extra property and now you can use it like this
channel = Channel.objects.first()
print(channel.active_posts.count())
0👍
I’m guessing that at the moment, you’re doing something like:
def channels_and_posts_for_user(user):
for channel in user.channel_membership:
posts = channel.channel_posts.all().filter(deleted__isnull=True)
channels_and_posts.append(channel, posts)
return channels_and_posts
and you’d like to get rid of that filter on every single call?
It is a pain, I agree, I’ve been trying to do something similar with an ‘archived’ variable in some of the models for my webapp.
I don’t believe there’s a way around it. You can create a custom manager like so:
class ChannelManagerWithUndeleted(models.Manager):
def get_queryset(self):
return super(ChannelManagerWithUndeleted, self).get_queryset().filter(deleted__isnull=True)
class Channel(models.Model):
#...
objects = models.Manager() # Default Manager
undeleted = EntryManager() # Custom Manager
and then access the objects directly via Channel.undeleted.all()
instead of Channel.objects.all
, but you still need to specify this new manager on related calls anyway, and it ends up almost as verbose (if a little more DRY):
channels_and_posts = []
for channel in user.channel_membership:
posts = channel.channel_posts.all(manager='undeleted').all()
channels_and_posts.append(channel, posts)
This is also a relevant post: How to use custom manager with related objects?.
I think it’s complicated because everyone wants slightly different behaviour in the different situations. e.g. I want my archived ‘Events’ to still be able to run reports, but not show up for the end user to select, so I’m using a custom manager everywhere consumer-facing.
If all you want to do is count them later for reporting, perhaps an option is to add a channel_deleted_posts
ManyToManyField and move the Post (without deleting it) from channel_posts
to channel_deleted_posts
. Hooks necessary, I’m afraid.
I really hope there’s a better answer and that what you want is trivial. I’d love to be proven wrong! 🙂