2017-02-13 66 views
0

我正在处理涉及通道/帖子机制的项目。我目前正在通过将名为“已删除”的字段设置为删除时间戳来实现“删除”帖子的功能。它需要保持历史意义(最后的活动),并追踪那些煽动性的人(该服务是整个项目的基于特权的部分)。Django ORM根据字段值过滤相关对象?

models.py

class Post(models.Model): 
    deleted = models.DateTimeField(null=True, blank=True) 
    created_date = models.DateTimeField(auto_now_add=True) 
    updated_date = models.DateTimeField(auto_now_add=True) 
    post_text = models.CharField(max_length=1000) 
    post_to = models.ForeignKey('Channel', related_name='post_to_channel') 
    post_from = models.ForeignKey(User, related_name='user_from_post') 

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() 

class Membership(models.Model): 
    channel = models.ForeignKey(Channel) 
    channel_user = models.ForeignKey(User, related_name='channel_membership') 
    join_date = models.DateTimeField(auto_now_add=True) 

我有一个更新的“删除”端点“后”对象的领域是从零时间戳。那么我该如何避免在“频道”级别查询时返回所有包含时间戳的帖子,通过他们的关系和单独的序列化程序加载帖子?基本上,我需要能够查询“频道”,并获得我参与的频道列表,然后通过他们与ManyToMany的关系,使用“发布”加载所有相关帖子,排除那些在“已删除”字段中具有值的用户。这可能不需要为每个通道调用ORM,然后过滤掉已删除的帖子?要清楚的是,如果存在已删除的帖子,则“频道”仍然应该通过,只有“帖子”本身应该被隐藏。

如果我没有提供足够的信息,请让我知道你需要看什么。

如果答案是没有重复的ORM调用,这是不可能的,建议其他选项将被赞赏,其中包括权衡将这些帖子归档到重复模型的选项,而不会在这些情况下调用钩子并删除原件。

编辑1: 添加的属性在所选择的答案指出,然而它不能看到self.channel_posts。 models.py

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 get_viewable_posts(self): 
     print (self.channel_users) # prints [] 
     print (self.channel_posts) # prints [] 
     return CourtyardPost.objects.filter(deleted__isnull=True, courtyard_post_to=self.pk) #works, but adds IO strain 

目前,如上所示它是每个通道的ORM呼叫,但打印self.channel_postsself.channel_users返回一个空列表,在所有方案。该物业被称为Django的REST框架的串行器的一部分如下面执行:

class CourtyardChannelSerializer(serializers.ModelSerializer): 
    current_user = serializers.SerializerMethodField('_user') 
    post_to_channel = CourtyardPostSerializer(many=True, source='get_viewable_posts', read_only=True) 
    most_recent = CourtyardPostSerializer(many=True, source='latest_post', read_only=True) 
    channel_users = CourtyardUserSerializer(many=True, read_only=True) 
) 
invite_list = serializers.ReadOnlyField(source='get_invitation_set', required=False) 

    def _user(self, obj): 
     user = self.context['request'].user.username 
     return user 

回答

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) 

很简单,只是增加了一个额外的属性,现在你可以使用它像这样

channel = Channel.objects.first() 
print(channel.active_posts.count()) 
+0

我居然遇到了一个问题,试图以此为-是,由于某种原因,自' .channel_posts'是一个空数组,无论是否在属性点(通过打印)过滤。我最终需要将其重新过滤为所有帖子的过滤查询集,但是这种方式在大规模(由于有太多数据库调用)的情况下效果不佳,为什么它会显示为空?你的答案仍然是最干净的,只是希望它可以像你写的那样工作,而不是我的临时版本。无论哪种方式,感谢您的帮助和时间! – AntonMiles

+0

如果您完全按照原样运行代码,那么显然您会在数据库中为“第一个”通道获取active_posts。由于Channel.objects.first()返回数据库中的第一个通道,因此可以使用 。 难道第一个频道没有帖子吗? – Ramast

+0

我调整了它,允许它使用'active_posts'作为序列化程序ManyToMany关系表示形式的源代码,我将编辑问题来说明这一点,但它从不会在我的默认用户的任何通道中看到任何内容,谁在开始删除功能之前拥有可用的帖子,以及之后发布的人员(可以工作,并且可以通过不同的端点查看)。它仍然是最好的答案,并且将它交换为查询集合,只是希望减少数据库IO应变。 *编辑清晰。 – AntonMiles

0

我猜测,此刻,你正在做的是这样的:

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 

,你会喜欢在每一次通话中摆脱那个过滤器?

这是一个痛苦,我同意,我一直在尝试在webapp的某些模型中为'archived'变量做类似的事情。

我不相信有一种解决方法。您可以创建自定义的经理像这样:

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 

,然后直接通过Channel.undeleted.all()代替Channel.objects.all访问的对象,但你仍然需要在related calls anyway指定这个新的经理,并且它几乎冗长结束了(如果多一点干):

channels_and_posts = [] 
for channel in user.channel_membership: 
    posts = channel.channel_posts.all(manager='undeleted').all() 
    channels_and_posts.append(channel, posts) 

这也是一个相关的职位:How to use custom manager with related objects?


我认为这很复杂,因为每个人都希望在不同情况下有些不同的行为。例如我希望我的归档“事件”仍然能够运行报告,但不会显示给最终用户选择,所以我使用的是面向消费者的自定义管理器。

如果你想要做的就是后来为报告数得过来,也许是一个选择是增加一个channel_deleted_posts ManyToManyField和移动邮政(而不删除)从channel_postschannel_deleted_posts。恐怕,挂钩是必要的。

我真的希望有一个更好的答案,你想要的是微不足道的。我很想被证明是错误的! :)

相关问题