I'm working on a Quiz app and one question gets uploaded every week in a month (4 ques/month). Now I want to make sure that a logged in user can only attempt the question twice per week and not more than that. How can I do this using throttling or any other way? Here's my Quiz model:
Days = (
("Mon", "Monday"),
("Tue", "Tuesday"),
("Wed", "Wednesday"),
("Thu", "Thursday"),
("Fri", "Friday"),
("Sat", "Saturday"),
("Sun", "Sunday")
)
class QuizDetail(models.Model):
name = models.CharField(max_lenght=255, blank=False, null=False)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
publisehd_week_day = models.CharField(max_length=255, choices=Days)
The published_week_day can change every month, so basically one month it can be Tuesday and next month it can be Thursday.
Note: If in a month published_week_day is Tuesday and a user attempts last week's quizz on Monday and exhausts his two attempts then on Tuesday he should be able to attempt as it will be a fresh quizz.
Thanks in advance.
CodePudding user response:
Store it in another field
I am assuming end_date
only stores the last time the quiz ended.
Create a field, say count
. Now increase count
by 1 everytime a test is attempted. If it reaches above 2, dont allow the quiz to be taken.
What about resetting it? You could calculate it every single time you make the request. However this is clearly extremely ineffiecient. Therefore, I would do something like so:
- Create another process.(Have a look at Simple approach to launching background task in Django)
- That process constantly searches through the database at fixed intervals.
- If it finds that a week has passed since the last time the user took the test, it resets the count to 0. To do this simple subtract current datetime(
datetime.now()
) withend_time
and compare it to 2 weeks.
CodePudding user response:
You have to create one model which basically would have a relationship with your QuizDetail
model
class UserQuizAttempt(models.Model)
quiz = models.ForeignKey(QuizDetail, on_delete=models.CASCADE)
user = models.ForeginKey(User, on_delete=models.CASCADE)
attempt_made_on = models.DateTimeField(auto_now_add=True)
so in your views.py file, where the user will make an API call to attempt the quiz you have to check whether the user has made any attempt for that particular quiz in that particular week. If it is exceeding 2 then just return a response saying that he's exceeding the limit of the attempt for the week.
a basic example could look like this
from datetime import date
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
class QuizAPI(APIView):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def check_user_attempts(self, request, quiz_instance):
current_week = date.today().isocalendar()[1]
attempts = UserQuizAttempt.objects.filter(attempt_made_on__week=current_week=current_week, quiz=quiz_instance, user=request.user)
if attempts.count() > 2:
return False
return True
def post(self, request):
quiz_id = request.data.get('quiz_id')
quiz_instance = QuizDetail.objects.get(id=quiz_id)
if self.check_user_attempts(request, quiz_instance):
UserQuizAttempt.objects.create(quiz=quiz_instance, user=request.user)
# your logic goes here
...
else:
return Response("Your attempts exceeding for the week! Please try next week", status=status.HTTP_406_NOT_ACCEPTABLE)
So with this, you will have the history of the user's attempt made on the quiz which can be used for reporting or something.