2017-12-04 10 views
0

Django Rest Frameworkのtutorialにあるコードに投票機能を追加しようとしています。スニペットモデルの上に、私は投票モデルを追加しました:Django Rest FrameworkでシリアライザでFKを更新する方法

class Vote(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    voter = models.ForeignKey(User, on_delete=models.CASCADE) 
    snippet = models.ForeignKey(Snippet, related_name='votes', on_delete=models.CASCADE) 

    class Meta: 
     ordering = ('created',) 

は、スニペットに、ユーザー投票を投稿して検証した後、私は今、スニペットが受信した投票数を更新したい私は、スニペットモデルに追加( number_of_votesフィールド)。

私はそのような私のVoteSerializerのメソッドを作成して、それをやっている:

class VoteSerializer(serializers.HyperlinkedModelSerializer): 
    voter = serializers.ReadOnlyField(source='voter.username',validators=[UniqueValidator(queryset=VoteUp.objects.all(), message=already_voted)]) 
    snippet = serializers.PrimaryKeyRelatedField(queryset=Snippet.objects.all()) 

    def validate(self, data): 
     # ... my validation function 

    def create(self, validated_data): 
     obj = Vote.objects.create(**validated_data) 
     obj.snippet.number_of_votes += 1 
     obj.snippet.save() 
     return obj 

それはうまく動作しますが、私はそれはそれを行うには良い方法かいないかどうか分かりません。より良い方法がありますか?

+0

これはあなたの質問に対する回答ではありません。しかし、私はなぜあなたが投票数を維持しているのだろうと思っています。スニペットに関連付けられている各投票にスニペットIDを設定して、数を取得するだけでカウントできます。 –

+0

'number_of_votes'変数の目的は何ですか?あなたがしたいのは、各スニペットの投票数を知っているだけであれば、外部キーから作られたクエリーセットから行うことができるはずです。 'snippet.vote_set.count()'は、 'snippet'との外部キーの関係を持つ投票数を返すべきです – MCBama

+0

私は、多くのユーザーが注文したスニペットのページを表示したいと思うならば、降順投票数では、計算は1回だけ行われます。 – Patrick

答えて

1

しようとすることができ、 "より良い" の方法のカップル:

上書き保存方法

class Vote(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    voter = models.ForeignKey(User, on_delete=models.CASCADE) 
    snippet = models.ForeignKey(Snippet, related_name='votes', on_delete=models.CASCADE) 

    class Meta: 
    ordering = ('created',) 

    def save(self, *args, **kwargs): 
    # ensure model is being created and not just modified: 
    if not self.pk: 
     # increment snippet vote counter 
     self.snippet.number_of_votes += 1 
     self.snippet.save() 

    # call base save method to ensure proper handling 
    super().save(*args, **kwargs) 

あなたのDjangoプロジェクトのための信号の設定をしたら

郵便保存信号を使用しますdocumentationに続いて、次のような信号を作成することができます:

from django.dispatch import receiver 
from django.db.models.signals import post_save 
# make sure you import Vote here. I'm not sure of your project 
# setup so I can't write the import for you. 

@receiver(post_save, sender=Vote) 
def update(sender, instance, created, **kwargs): 
    # only increment on model creation 
    if created: 
    instance.snippet.number_of_votes += 1 
    instance.snippet.save() 

すべての正直なところ、私はかなり確信していますが、snippet.vote_set.count()は非常に高速な呼び出しであり、カウンタの代わりに使用したい場合は実行時間を妨げません。カウンターをインクリメントするかどうかを覚えておくと、カウンターを減らす必要があります。また、誰かがレコードを削除した場合、カウントはオフになります。

関連する問題