Dynamic View not displayed - django

I am trying to take a quiz and if you answer a question wrong you see that question get added to a list of wrong questions.
Questions can be used in multiple quizes so I can't hard code ask question_1 then question_2 etc.
When I load the page I see the first question but then if I submit or refresh I see the right.html template. It doesn't ask all of the questions.
It should ask all of the questions before rendering the right.html page
for question in quiz.questions.all():
if question not in asked_questions:
asked_questions.append(question)
return answer_question(request, quiz_id, question.id, module_list)
models.py
class Choice(models.Model):
choice = models.CharField(max_length=64)
def __unicode__(self):
return self.choice
#create a multiple choice quiz to start
class Question(models.Model):
question = models.CharField(max_length=64)
answer = models.CharField(max_length=64)
choices = models.ManyToManyField(Choice)
module = models.CharField(max_length=64)
def __unicode__(self):
return self.question
class Quiz(models.Model):
name = models.CharField(max_length=64)
questions = models.ManyToManyField(Question)
def __unicode__(self):
return self.name
views.py
asked_questions = []
module_list = []
module_list.append('test')
def take_quiz(request, quiz_id):
quiz = Quiz.objects.get(id=str(quiz_id))
for question in quiz.questions.all():
if question not in asked_questions:
asked_questions.append(question)
return answer_question(request, quiz_id, question.id, module_list)
#quiz is over
return render (request, 'right.html')
def answer_question(request, quiz_id, question_id, module_list):
question = Question.objects.get(id=question_id)
#module_list = []
if request.method == 'POST':
form = QuestionForm(request.POST)
choices = [(i, i) for i in question.choices.all()]
form.fields['selection'].choices = choices
if form.is_valid():
if form.cleaned_data['selection'] != str(question.answer):
module_list.append(question.module)
return take_quiz(request, quiz_id)
else:
form = QuestionForm()
choices = [(i, i) for i in question.choices.all()]
form.fields['selection'].choices = choices
return render(request, 'answer_question.html', {'question':question, 'form':form, 'module_list':module_list})

If you plan on hosting this and making it available on the web, you should really start over. You shouldn't use lists like that to store stuff, you should use sessions or the cache instead. Also, you would be better off using a FormWizard for the quiz since it is designed to do exactly what you are trying to do: handle multiple forms and process them.

Maybe you should try
return HttpResponseRedirect(reverse('answer_question', args=[quiz_id, question_id, module_list]))
to redirect your view to another view.
p.s.: reverse should contain the name of your 'answer_question' view

Related

Calling django query sets when user needs them

I have been going back and forward with ideas doing this and none of them has worked so I'm gonna ask for ideas. I have model called "List" that users can create for example "Sleep" Then they have input where they select one of their lists and can add value for example 8. Good sleep! After that user sees a graph based on the data that he/(she has entered. All that is already working but I cannot seem to find a way to get data organized.
I'm trying to do it so list "sleep" calls all it's values to the graph and then other list lets say "money" shows all its money values. I am using chart.js to draw the graphs and I dont care if they are all at the same time on the screen or if one by one but for somereason I cannot call these querysets properly. Only way it works is if I use .all() and that wont work since I have multiple users.
Models:
class List(models.Model):
name = models.CharField(max_length=100, default="")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='lists')
def __str__(self):
return self.name
class Meta:
unique_together = ['name', 'user']
class DataItem(models.Model):
data = models.IntegerField(default=0)
list = models.ForeignKey(List, on_delete=models.CASCADE, related_name='data_items')r code here
Views
#login_required
def app(request):
form = list_form
form2 = data_form
user = request.user.pk
user_lists = List.objects.filter(user=user)
context = {'user_lists': user_lists, 'form': form, 'form2': form2}
return render(request, 'MyApp/app.html', context)
#require_POST
def addItem(request):
form = list_form(request.POST)
if form.is_valid():
user = request.user
new_list = List(name=request.POST['text'], user=user)
new_list.save()
return redirect('/app/')
#require_POST
def addData(request):
form = data_form(request.POST)
if form.is_valid():
new_data = DataItem(data=request.POST['data'], list=List.objects.get(id=request.POST['selection']))
new_data.save()
return redirect('/app/')
"addItem" adds an list (money and sleep)
"addData" adds an value to selected list
I have no glue where to start making what I descibed.. Should I filter the data sets in main view? make own view for it and call them with buttons?
Please be specific if you have some idea how to make that kind of function since i'm pretty new to django. Thanks :)
I take it you want to get all lists that a User has created, and then create graphs for them. First of all, I recommend adding a DateTimeField() to the DataItem model. For example: created = models.DateTimeField(auto_now_add=True).
Then, in a view, you can get all of the data for a users list like this:
#login_required
def app(request):
form = list_form
form2 = data_form
user = request.user.pk
user_lists = List.objects.filter(user=user)
list_data = {}
for list in user_lists:
list_data[list.name] = DataItem.objects.filter(list=list)
context = {'user_lists': user_lists, 'form': form, 'form2': form2, 'list_data': list_data}
return render(request, 'MyApp/app.html', context)
This will save all of the data you need in list data. If you took my advice at the beginning of the response, you could also sort it by created to get chronological. In the template, you can loop through this list. The key is the name of the list, and the value will be a queryset of the data entries.

how does the "Favourate" button in StackOverFlow works?

i am creating a forum for my website. i would like to know how does the "This is your favourate question" button in StackOverFlow webpage(ie this website) works?
i am using django.
i created models such as:
models.py
class Question(models.Model):
user=models.ForeignKey(User)
created=models.DateTimeField(auto_now_add=True)
topic=models.ForeignKey(Topic)
question=models.TextField()
tags=models.CharField(max_length=50,blank=True)
class Favourites(models.Model):
'''
Does this your Favourite Question'''
user=models.ForeignKey(User)
favourite=models.BooleanField(default=False)
question=models.ForeignKey(Question)
also i would like to know how to create view to get total favourites for a particular question and also any other modified models.
You probably don't need the 'favourite' field. You can assume that, if there is entry in your table for a given question, related to a given user, that question is that users favorite.
You'll need to create a view which will take a question id, and mark it as the currently logged in user's favorite:
def mark_as_favorite(request, question_id, *args, **kwargs):
if request.user.is_authenticated():
question = get_object_or_404(Question, id=question_id)
favorite = Favourite.objects.create(user=request.user, question=question)
return HttpResponse("Marked")
else:
return HttpResponseForbidden("User is not logged in")
Finding the total favorites for a given question is easy:
def question(request, quesiton_id, *args, **kwargs):
question = get_object_or_404(Question, id=question_id)
favorites = Favourites.objects.filter(question=question)
favorites_count = favorites.count()
return render_to_response('template', {'question':questions, 'favorites_count':favorites_count}, context_instance=RequestContext(request))
i just edited jack shedd's answer
def mark_as_favorite(request, question_id, *args, **kwargs):
if request.user.is_authenticated():
fav, created = Favourite.objects.get_or_create(user=request.user, question=question)
if created:
return HttpResponse("Marked")
else:
fav.delete()
return HttpResponse("Un Marked")
else:
return HttpResponseForbidden("User is not logged in")

Using two parameters to delete using a Django DeleteView [duplicate]

This question already has answers here:
Example of Django Class-Based DeleteView
(4 answers)
Closed 6 years ago.
I am trying to delete a report from a particular client, so currently in my url.py i am passing the client id and the report id, hoping to delete report Y from client X. I could have done this using def ReportScheduleDeleteView(request): , but was hoping to use the Class-Based DeleteView.
I had a look at this example but wasn't able to blend with my code.
So here is my code.
urls.py
url(r'^jsclient/(?P<pk>\d+)/report/(?P<r_pk>\d+)/delete/$', ReportScheduleDeleteView.as_view(), name="report-delete"),
models.py -
class JSClient(models.Model):
name = models.CharField(max_length=255, unique=True)
clientAccount = models.CharField(max_length=255)
....
class ReportSchedule(models.Model):
client = models.ForeignKey(JSClient)
schedRepName = models.CharField(max_length=255)
reportType = models.CharField(max_length=255, choices=REPORT_TYPE)
....
views.py :
class ReportScheduleDeleteView(DeleteView):
model = ReportSchedule
template_name = "report/report_confirm_delete.html"
success_url = lazy(reverse, str)('jsclient-list')
I am sure there must be a way of doing this using the Class-Based DeleteView, any help on this is appreciated.
Thanks to the tip from EsseTi and CCBV site I managed to crack out the solution for my problem. It might have been obvious
class ReportScheduleDeleteView(DeleteView):
model = ReportSchedule
template_name = "report/report_confirm_delete.html"
success_url = lazy(reverse, str)('jsclient-list')
# Get the parameters passed in the url so they can be used in the
# "report/report_confirm_delete.html"
**UPDATE:**
def get_object(self, queryset=None):
if queryset is None:
queryset = self.get_queryset()
client = self.kwargs['pk']
report = self.kwargs['rpk']
queryset = ReportSchedule.objects.filter(client_id=client, id=report)
if not queryset:
raise Http404
context = {'client_id':client, 'report_id':report}
return context
# Override the delete function to delete report Y from client X
# Finally redirect back to the client X page with the list of reports
def delete(self, request, *args, **kwargs):
client = self.kwargs['pk']
report = self.kwargs['rpk']
clientReport = ReportSchedule.objects.filter(client_id=client, id=report)
clientReport.delete()
return HttpResponseRedirect(reverse('report-list', kwargs={'pk': client}))
Hope it helps some one.
it's simliar to this one Example of Django Class-Based DeleteView
redefine def get_object(self, queryset=None) and do your checking inside.
using kwargs you should be able to get the parameters from url.

How do I use more than one app on the same page but not all pages

So I have the standard django tutorial polls app and I made a little blog app. Is there a simple way to add a poll to some of the blog posts but not all.
I've found this:
from django.models.polls import polls
from django.models.blogs import posts
def my_view(request):
return render_to_response("template_name", {
"poll_list" : polls.get_list(),
"post_list" : posts.get_list(),
}
But how do I pick which poll I want in the template and if I add it to the template won't it show up in every post? I feel like im seriously over-thinking or under-thinking this. Any advice or links would be appreciated. Thanks.
models.py #for the blog app
class Post(models.Model):
title = models.CharField(max_length=60)
description = models.TextField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
def display_mySafeField(self):
return mark_safe(self.body)
def __unicode__(self):
return self.title
views.py # for blog class
def post(request, pk):
"""Single post with comments and a comment form."""
post = Post.objects.get(pk=int (pk))
comments = Comment.objects.filter(post=post)
d = dict(post=post, comments=comments, form=CommentForm(), user=request.user,
months=mkmonth_lst())
d.update(csrf(request))
return render_to_response("post.html", d)
I want to add a poll to a post but not all of them.
Add something which will indicate which poll is associated to which model. You can use ForeignKey, ManyToManyField, GenericForeignKey, OneToOneField, etc and then use that indicator to get poll/s associated to post/s .

(ab)using Django form wizard to do my bidding- is this even possible?

I've been charging head-first against a brick wall for days now, it's time to ask people who are smarter and more experienced than I for advice.
Context: As part of my web app I'm building a quiz application where users can answer quizzes consisting of multiple choice questions. The questions are all user generated so I have a couple of interesting problems at the same time:
a) I have to construct the quiz-question form(radioselect widget) dynamically on the fly. Since both the answer options and the question text are user-generated (models 'Question' and 'Answer'), I have to run a query in the view and then pass the variables to my form's init. That way I can populate the choices and overwrite the label with the question text:
from forms.py:
#it's not very clean, there's a lot of legacy code in there...
class AnsweredQuestionForm(forms.ModelForm):
class Meta:
model = AnsweredQuestion
widget = {
'id': forms.TextInput, # needed for formset that I was using
}
question_field = forms.ModelChoiceField(
empty_label='Gee, this is tough. Can you show me some hints?',
widget=forms.RadioSelect,
queryset=Question.objects.all(),
required=True,
help_text='',
error_messages={'required': 'Please pick an answer'},
)
def __init__(self, *args, **kwargs): # I'm using django crispy-forms
self.helper = FormHelper()
self.helper.form_method = 'POST'
self.helper.form_id = ''
self.helper.form_class = ''
self.helper.form_action = ''
self.helper.form_tag = False
self.helper.help_text_inline = True
self.helper.render_unmentioned_fields = False
self.helper.form_error_title = 'Form Errors'
self.helper.layout = Layout(
Field('question_field'),
Field('id', css_class='hidden'),
)
self.question = kwargs.pop('question', None)
super(AnsweredQuestionForm, self).__init__(*args, **kwargs)
self.fields['question_field'].label = self.question.question_text
self.fields['question_field'].queryset = self.question.answers.all()
b) That means that the quiz-question forms are modelforms (I have a model called 'AnsweredQuestions' that saves instances of given answers. There's also a model 'TakenQuiz' for the quiz). I create an instance of TakenQuiz when a user starts a quiz and of AnsweredQuestion when she answers a quiz-question and the form gets saved.
from models.py
class AnsweredQuestion(models.Model):
question = models.ForeignKey(Question, null=True, blank=True)
given_answer = models.ForeignKey(Answer, null=True, blank=True)
taken_quiz = models.ForeignKey(TakenQuiz, related_name="answered_questions", null=True, blank=True)
date = models.DateTimeField(editable=False)
correct = models.BooleanField(default=False)
class Meta:
verbose_name = 'answered question'
verbose_name_plural = 'answered questions'
def save(self, *args, **kwargs):
""" On save, update timestamp."""
if not self.id:
self.date = datetime.datetime.now()
super(AnsweredQuestion, self).save(*args, **kwargs)
def __unicode__(self):
return unicode(self.given_answer)
from views.py(test view):
def take_quiz(request, category_slug, course_slug, module_slug, quiz_number):
user = request.user
category = Category.objects.get(slug=category_slug)
course = Course.objects.get(category=category, slug=course_slug)
module = Module.objects.get(course=course, slug=module_slug)
quiz = module.quizzes.get(number=quiz_number)
quiz_questions = Question.objects.filter(quiz=quiz)
...
else:
taken_quiz = TakenQuiz()
aq_form = AnsweredQuestionForm(question=question)
c) a quiz can consist of a variable number of quiz-questions, I only set a max limit. So pretty much everything is dynamic :(
So here are my specific questions:
How can I access the URL params and use them for my queries if I'm using a formwizard? (btw, I hate class-based generic views for that) I tried to make the number of questions dynamic, but haven't figured out yet how exactly I can pass the variable (len(quiz_questions) to the wizard... My url looks like the following, and unfortunately I need to pass all of it either to the template context or to the forms' init:
from urls.py:
url(r'^(?P<category_slug>[-\w]+)/(?P<course_slug>[-\w]+)/(?P<module_slug>[-\w]+)/(?P<quiz_number>\d+)/$', quiz_wizard, name='quiz_wizard'),
quiz_wizard = QuizWizard.as_view(named_quiz_forms)
named_quiz_forms = [('quiz_question_%d' % i, AnsweredQuestionForm) for i in xrange(0, len(quiz_questions))]
Should I even bother to try to bend the formwizard to do what I need? I've spent a lot of time on google research and the source code, and I found potential solutions for some of the problems, but not for all. Especially not for all of them at the same time...
I would probably have to overwrite at least all of these:
class QuizWizard(NamedUrlSessionWizardView):
def get_form(self, step=None, data=None, files=None):
form = super(QuizWizard, self).get_form(step, data, files)
...
return form
def get_form_kwargs(self, step):
return {}
def get_form_instance(self, step):
return self.instance_dict.get(step, None)
And finally: Any recommendation how I should handle the quizzes if I can't use the formwizard? Using the formwizard just seemed... cleaner to me vs just using views for every single quiz-question. The big advantages of the wizard are that I don't have to take care of saving the form data somewhere until the whole quiz is completed and validated and that the wizard keeps track of the number of steps and the current step for me. I'm a newbie and not really all that great at writing this kind of advanced stuff from scratch.
Thanks a lot for your help, any advice or help is highly appreciated!!