2👍
I can’t tell you how much I learned by looking at the class based view source code. Once you’ve seen it, it becomes very easy to modify your class object to do what you want. In your case, if you add a post
method to your class, it will be called in the event of a post to the url mapped to the view.
def post( self, request, *args **kwargs ):
# receive the post, process the rating, return your JSON response
In response to your comments
Since you’re wanting users to be able to upvote/downvote from a ListView, you will need some way of identifying the post being voted on to the POST view which handles the request.
So if you were to send the id of the blogpost along with the vote, you could grab that model and update it accordingly.
assuming a model like this
class BlogPost( models.Model ):
upvotes=models.IntegerField( default=0 )
downvotes=models.IntegerField( default=0 )
def get_score( self ):
return self.upvotes - self.downvotes
score=property( get_score )
yourtemplate.html
{% for post in object_list %}
<div class="blogpost" data-pk="{{post.pk}}">
<span class="score">{{post.score}}</span>
<a class="upvote" href="#">Upvote</a>
<a class="downvote" href="#">Downvote</a>
</div>
{% endfor %}
yourjavascript.js
$('.blogpost').on( 'click', '.upvote,.downvote', function( e ){
e.preventDefault();
var id=$( this ).closest('.blogpost').data('pk'),
upvote=$( this ).is('.upvote'),
xhr=$.ajax({
url: location.href,
type: 'post',
data:{ id: id, upvote: upvote ? 1 : 0 },
dataType: 'json'
});
xhr.done( function( data ){
// successful submission
});
});
views.py
class AwesomeDisplayListView(JSONResponseMixin,ListView):
model = BlogPost
template_name = "awesome_list.html"
paginate_by = '15'
context_object_name = "searchres"
def post( self, request, *args, **kwargs ):
id=request.POST.get('id')
upvote=int( request.POST.get('upvote') )
blogpost=BlogPost.objects.get( pk=id )
if upvote:
blogpost.upvotes=blogpost.upvotes + 1
else:
blogpost.downvotes=blogpost.downvotes + 1
blogpost.save()
return http.HttpResponse( json.dumps({ 'score': blogpost.score }) )
To expand further on my last comment, a Rating model might make this easier.
class BlogPost( models.Model ):
title=models.CharField( max_length=100 )
def get_score( self ):
return self.ratings.filter( up=True ).count() - self.ratings.filter( up=False ).count()
score=property( get_score )
class Rating( models.Model ):
blogpost=models.ForeignKey( BlogPost, related_name="ratings" )
user=models.ForeignKey( User )
up=models.BooleanField( default=True )
class Meta:
unique_together=('blogpost','user',)
Then in your post view
def post( self, request, *args, **kwargs ):
id=request.POST.get('id')
upvote=bool( int( request.POST.get('upvote') ) )
blogpost=BlogPost.objects.get( pk=id )
rating, is_new=Rating.objects.get_or_create( user=request.user, blogpost=blogpost )
if rating.up != upvote:
rating.up=upvote
rating.save()