2017-02-13 4 views
0

私はチャネル/ポストメカニズムを含むプロジェクトに取り組んでいます。私は現在、削除された時のタイムスタンプに "deleted"という名前のフィールドを設定することによって、投稿を "削除"する機能を実装しています。歴史的意義(最後の活動)と炎症を起こしている人々(このサービスはプロジェクト全体の特権に基づく部分)を追跡する必要があります。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と "Post"との関係を通して、 "deleted"フィールドに値を持つものを除くすべての関連Postをロードする必要があります。これは、各チャンネルの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_postsまたはself.channel_usersを印刷すると、すべてのシナリオでは、空のリストを返します。下記実施されるようなプロパティはDjangoの残りFrameworkのシリアライザの一部として呼び出されます。

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'はプロパティのポイントで(印刷を介して)フィルタリングされているかどうかにかかわらず、空の配列です。私はそれをすべての投稿のフィルタ付きクエリーセットに書き直す必要がありましたが、これは大規模に(多くのDB呼び出しのために)うまく動作しません。あなたは答えがまだきれいです、ちょうどあなたが私の一時的なバージョンの代わりにそれを書いたように動作することを望んでいる。いずれにせよ、あなたの助けと時間をありがとう! – AntonMiles

+0

コードを正確に実行すると、明らかにDBの "最初の"チャンネルのactive_postsが得られます。 Channel.objects.first()はDB内の最初のチャンネルを返してから です。 最初のチャンネルに投稿がないことはありますか? – Ramast

+0

シリアライザのManyToMany関係の表現のソースとして 'active_posts'を使用できるようにしましたが、これを説明するために質問を編集しますが、デフォルトのユーザのチャンネルには何も表示されません。削除機能を開始する前に利用可能なポストを所持していたユーザー、その後ポストしたユーザー(別のエンドポイントを介して表示され、動作します)。それは依然として最良の答えです。そして、クエリーセットのためにそれを交換することは、DB 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のためのいくつかのモデルで 'アーカイブされた'変数と同様のことをしようとしています。

私は周りに道があるとは思わない。 (もし

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.objects.allChannel.undeleted.all()経由で直接オブジェクトにアクセスしていますが、まだrelated calls anywayにこの新しいマネージャーを指定する必要があり、それはほぼ同じ冗長終わる:あなたはそうのようなカスタムマネージャを作成することができますもう少しDRY):

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_postsからchannel_deleted_postsに移動することをお勧めします。フックが必要です、私は恐れています。

私は本当に良い答えがあることを望み、あなたが望むものは簡単です。私は間違っていることを証明したい! :)

関連する問題