I'm building an app to show random questions to users by categories. Each user should vote on question by "yes", "no" or "na". The app counts the votes per questions, each user can vote once per question.
The questions should appear randomly to the users and shouldn't appear more than once per user (user can't proceed without voting).
models.py:
class Category(models.Model):
name = models.CharField(max_length=500, null=False)
parent = models.ForeignKey("self", null=True, default=None)
class Question(models.Model):
question = models.CharField(max_length=500, null=False, blank=False)
title = models.CharField(max_length=100, null=False, blank=False)
category = models.ForeignKey(Category, null=True, default=None, blank=True)
no_count = models.BigIntegerField(default=0)
yes_count = models.BigIntegerField(default=0)
na_count = models.BigIntegerField(default=0)
user = models.ForeignKey(User, null=True, default=None)
rand = models.FloatField(null=True, default=0)
def save(self, *args, **kwargs):
self.rand = random.random()
super(Picture, self).save(*args, **kwargs)
class Vote(models.Model):
VOTE_CHOICES = (
(1, 'Yes'),
(2, 'No'),
(3, 'N/A'),
)
user = models.ForeignKey(User)
question = models.ForeignKey(Question, null=True, default=None)
user_vote = models.IntegerField(choices=VOTE_CHOICES)
class UserSettings(models.Model):
user = models.OneToOneField(User)
categories = models.CommaSeparatedIntegerField(max_length=1000, null=True)
views.py:
class GetQuestions(generics.ListAPIView):
model = Question
serializer_class = QuestionSerializer
def get_queryset(self):
user = self.request.user
lookup = dict()
categories = user.usersettings.categories
if categories is None:
categories = Category.objects.filter(~Q(parent=None)).values_list('id', flat=True)
else:
categories = ast.literal_eval(categories)
lookup['category__in'] = categories
voted = Vote.objects.filter(user=self.request.user).values_list('question')
questions = Question.objects.filter(**lookup).exclude(id__in=voted).order_by('rand')
return questions
class NewVote(generics.CreateAPIView):
model = Vote
serializer_class = VoteSerializer
def post(self, request, *args, **kwargs):
current_vote = Vote.objects.filter(user=request.user, picture=int(self.request.DATA['question']))
if current_vote:
return HttpResponseForbidden()
return super(NewVote, self).post(request, *args, **kwargs)
def pre_save(self, obj):
obj.user = self.request.user
def post_save(self, obj, created=False):
if created:
vote_count = obj.vote.get_user_vote_display().lower().replace(" ", "")
vote_count += "_count"
count = getattr(obj.picture, vote_count)
setattr(obj.picture, vote_count, count + 1)
obj.picture.save()
On vote I just increment the relevant count on the question. My questions are:
- What is the best way to choose random question? Currently I've added random field on question and use order_by('rand') - is there a better way?
- What is the best way to choose question of categories that the user? currently I'm using filter category__in
- The most important one - How do I exclude questions that the user already voted on? currently I just select all questions from the vote table which user = request.user and using "NOT IN" - when scaling this is surely won't be good...
Concepts, code sample, links are welcome.
Many thanks