i am fairly new to Django and Python and have the following problem:
I have a quiz with multiple answers.
Every answer has a form attached to it, which posts data to a view that creates an objects from a Model.
But i cant post all forms, because its only posting the 5th one.
views.py:
def quiz(request, quiz_id=1):
cs = {}
cs.update(csrf(request))
height=75*Frage.objects.count()
height_menu = height + 10
if Frage.objects.count() == 0:
height = 170
height_menu = height
len_quiz = len(Quiz.objects.get(id=quiz_id).title)
count=Frage.objects.filter(quiz=quiz_id).count
count_aw = 0
aw = Frage.objects.filter(quiz=quiz_id)
cs.update({'quiz': Quiz.objects.get(id=quiz_id),
'Frage': Frage.objects.filter(quiz=quiz_id),
'len': len_quiz,
'hg': height,
'hg_m': height_menu,
'user': request.user,
'aw': Antwort.objects.all(),
'count': count,
'count_aw': count_aw})
return render_to_response('quiz.html', cs)
def check_view(request):
check = request.POST.get('aw_check', '')
user_id = request.POST.get('user_log', '')
user_act = User.objects.get(id=user_id)
frage_id = request.POST.get('frage', '')
frage = Frage.objects.get(id=frage_id)
antwort_id = request.POST.get('antwort', '')
antwort = Antwort.objects.get(id=antwort_id)
richtig = request.POST.get('richtig', '')
quiz_id = request.POST.get('quiz', '')
quiz = Quiz.objects.get(id=quiz_id)
res = Results(quiz=quiz, frage=frage, user=user_act, richtig=richtig, choice=check, aw=antwort)
res.save()
return HttpResponseRedirect('/quiz/all/')
template:
{% if Frage.count == 0 %}
<br>
<h1 id="main_link" style="text-align: center" align="center">Keine Fragen vorhanden!</h1>
{% endif %}
<ol>
{% for Frage in Frage %}
<li><div id="frage">{{Frage.content}}</div></li>
{% for aw in Frage.antworten.all %}
<form action="/quiz/check/" name="{{ aw.content }}" method="post">{% csrf_token %}
<label for="aw_check">{{ aw.content }}</label>
<input type="checkbox" name="aw_check" id="aw_check">
<input type="hidden" name="user_log" value="{{ user.id }}">
<input type="hidden" name="frage" value="{{ Frage.id }}">
<input type="hidden" name="antwort" value="{{ aw.id }}">
<input type="hidden" name="quiz" value="{{ quiz.id }}">
{% if aw.richtig %}
<input type="hidden" name="richtig" value=True>
{% else %}
<input type="hidden" name="richtig" value=False>
{% endif %}
<input type="submit" value="Abgeben" />
<br>
</form>
{% endfor %}
{% endfor %}
</ol>
<script language="javascript">
function call_submitforms(){
{% for Frage in Frage %}
{% for aw in Frage.antworten.all %}
setTimeout("document.{{ aw.content }}.submit()",1000);
{{ check.it }}
{% endfor %}
{% endfor %}
}
</script>
<input type="button" value="Abschicken" onclick="call_submitforms()" />
I think you should redesign your program. My understanding is that form submission can only handle one form. Here are some work-arounds using Django/Python. But, for your case, if you're designing a quiz, all of the answers should be part of a single form. Instead of returning {% for Frage in Frage %} I would do something like this (you'll have to redesign your models and views first):
//one form contains all questions
form action="/quiz/check/" name="{{ aw.content }}" method="post">{% csrf_token %}
//list the questions as part of that form
{%for Frage in quiz.Frages%}
<input type="hidden" name="user_log" value="{{ user.id }}">
<input type="hidden" name="antwort" value="{{ aw.id }}">
<input type="hidden" name="quiz" value="{{ frage.id }}">
{% endfor %}
//submit all of the data for each page of the quiz in one form
<input type="hidden" name="richtig" value=True>
{% else %}
<input type="hidden" name="richtig" value=False>
{% endif %}
<input type="submit" value="Abgeben" />
Related
views.py
def create(request):
choicenumber = 3
submitbutton = request.POST.get('submit', False)
choicebutton = request.POST.get('add_choice', False)
if choicebutton:
choicenumber += 1
render(request, 'polls/create.html', {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
})
if submitbutton:
new_question = Question.objects.create(question_text=request.POST.get('question_text', ''),
pub_date=timezone.now())
if new_question.question_text == '':
context = {
'questionfields': Question.__dict__,
'error_message': "No poll question entered.",
'choicenumber': choicenumber,
}
del new_question
return render(request, 'polls/create.html', context)
else:
for i in range(choicenumber + 1):
choice = request.POST.get(('choice' + str(i)), '')
if choice:
choice_obj = Choice.objects.create(question=new_question, choice_text=choice)
new_question.choice_set.add(choice_obj)
new_question.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
else:
return render(request, 'polls/create.html', context)
create.html
{% extends "polls/base.html" %}
{% block title %}Create a Poll{% endblock title %}
{% block header %}Create:{% endblock header %}
{% load custom_tags %}
{% block content %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:create' %}" method="post"> {% csrf_token %}
{% for field in questionfields %}
{% if field == 'question_text' %}
<label for="{{ field }}">{{ field|capfirst|replace }}:</label>
<input type="text" name="{{ field }}" id="{{ field }}">
<br>
{% endif %}
{% endfor %}
<br>
{% for choice in choicenumber|rangeof %}
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
<br>
<input type="button" name="add_choice" value="Add choice">
<br>
<br>
<input type="submit" value="Create" name="submit">
</form>
{% endblock content %}
I recently added the add_choice button to my template:
<input type="button" name="add_choice" value="Add choice">
Using this, I tried using a request.POST.get() to check if it has been clicked, and if so for it to increment 'choicenumber' and re-render the view with the increased value of choicenumber:
if choicebutton:
choicenumber += 1
return render(request, 'polls/create.html', {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
})
Since the increment causes choicenumber to increase, within the create.html the for loop for producing the input boxes for each choice --
{% for choice in choicenumber|rangeof %}
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
-- should loop once more than usual on the re-render. This does not happen however, and the website renders as originally.
Does anyone know how to make this work properly or improve my code? I am very new to the Django framework, so any advice would be great. Thanks!
EDIT::
updated views.py
def create(request):
choicenumber = 3
context = {
'questionfields': Question.__dict__,
'choicenumber': choicenumber,
}
submitbutton = request.POST.get('submit', False)
choicebutton = request.POST.get('add_choice', False)
if request.method == 'GET':
request.session['choicenumber'] = 0
if request.method == 'POST':
if choicebutton:
request.session['choicenumber'] += 1
if submitbutton:
new_question = Question.objects.create(question_text=request.POST.get('question_text', ''),
pub_date=timezone.now())
if new_question.question_text == '':
context = {
'questionfields': Question.__dict__,
'error_message': "No poll question entered.",
'choicenumber': choicenumber,
}
del new_question
return render(request, 'polls/create.html', context)
else:
for i in range(choicenumber + 1):
choice = request.POST.get(('choice' + str(i)), '')
if choice:
choice_obj = Choice.objects.create(question=new_question, choice_text=choice)
new_question.choice_set.add(choice_obj)
new_question.save()
return HttpResponseRedirect(reverse('polls:detail', args=(new_question.id,)))
else:
return render(request, 'polls/create.html', context)
EDIT 2::
updated create.html
{% extends "polls/base.html" %}
{% block title %}Create a Poll{% endblock title %}
{% block header %}Create:{% endblock header %}
{% load custom_tags %}
{% block content %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:create' %}" method="post"> {% csrf_token %}
{% for field in questionfields %}
{% if field == 'question_text' %}
<label for="{{ field }}">{{ field|capfirst|replace }}:</label>
<input type="text" name="{{ field }}" id="{{ field }}">
<br>
{% endif %}
{% endfor %}
<br>
{% for choice in {{ request.session.choicenumber }}|rangeof %}
# the update is here: choicenumber -> {{ request.session.choicenumber }}
# this defaults as 0 though, even if it is defined as 3.
<br>
<label for="choice{{ forloop.counter }}">Choice {{ forloop.counter }}:</label>
<input type="text" name="choice{{ forloop.counter }}" id="choice{{ forloop.counter }}">
<br>
{% endfor %}
<br>
<input type="button" name="add_choice" value="Add choice">
<br>
<br>
<input type="submit" value="Create" name="submit">
</form>
{% endblock content %}
NoReverseMatch at /project/users/1/stories/1/
Reverse for 'user' with arguments '('',)' not found. 1 pattern(s) tried: ['project/users/(?P[0-9]+)/$']
Does anyone have any idea why I face this error when I press "python manage.py runserver"? It used to work just fine and now it just doesn't. I've seen that the problem might be with user_id or user.id, but I can't really see it! Here is my code:
project/views.py
def story(request, user_id, story_id):
if story_id is not None:
story = get_object_or_404(Story, pk=story_id)
else:
story = Story()
story.user_id = user_id
if request.method == 'POST':
story.title = request.POST['title']
story.story = request.POST['story']
story.date = timezone.now()
story.save()
return HttpResponseRedirect(reverse('project:story', args=(user_id,)))
else:
context = {
'user_id': user_id,
'story_id': story_id,
'title': story.title,
'story': story.story,
'likes': story.likes,
'comments': story.comments
}
return render(request, 'project/story.html', context)
project/urls.py
urlpatterns = [
path('', views.index, name='index'),
path('register/<int:user_id>/', views.register, name='register'),
path('login/<int:user_id>/', views.login, name='login'),
path('users/<int:user_id>/', views.user, name='user'),
path('users/<int:user_id>/stories/<int:story_id>/', views.story, name='story'),
]
project/templates/project/story.html
{% extends "project/base.html" %}
{% block content %}
{% if story_id %}
<div class="post-preview">
<h2 class="post-title"> {{ story.title }}</h2>
<p class="post-subtitle">
{{ story.story }}
</p>
<p class="post-meta">Posted by
{{ story.author.username }}
on {{ story.date }}
<i class="fas fa-thumbs-up"> {{ story.likes }}</i>
<i class="fas fa-comment"> {{ story.comments }}</i>
</p>
</div>
<div class="post-preview">
<h2> Comments </h2>
{% for com in latest_comments %}
<div class="post-preview">
<p class="post-subtitle"> {{ comment.com }}</p>
</div>
{% endfor %}
</div>
<div class="post-preview">
<form action="{% url 'project:story' user.id story.id %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="text">Comment</label>
<textarea id="text" name="text"
class="form-control" placeholder="Comment" rows="4">{{ comment.com }}
</textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
{% else %}
{% if request.story.author.id == user.id %}
<form action="{% url 'project:story' user.id story.id %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="title">Title</label>
<input type="text" id="title" name="title"
class="form-control" placeholder="Title" value="{{ story.title }}"/>
</div>
<div class="form-group">
<label for="text">Story</label>
<textarea id="text" name="text"
class="form-control" placeholder="Story" rows="10">{{ story.story }}
</textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endif %}
{% endif %}
{% endblock %}
In your context we see:
context = {
'user_id': user_id,
'story_id': story_id,
'title': story.title,
'story': story.story,
'likes': story.likes,
'comments': story.comments
}
so the story variable does not contain a Story object, it contains its story attribute (probably, based on the rest of the view, a string).
Now in your template you write:
{% url 'project:user' story.author.id %}
but since story is a string, it has no .author attribute, so this will get evaluated to the string_if_invalid which is, unless you specified otherwise, the empty string ''.
You thus need to pass the story itself in your context to:
context = {
'user_id': user_id,
'story_id': story_id,
'title': story.title,
'story': story,
'likes': story.likes,
'comments': story.comments
}
Is there any way to select a specific object that is found in the results of a queryset like selecting an item in an array.
In arrays, you can select a specific item based on its position:
arrayName = {55, 33, 34, 23}
arrayName[2]
result = 34
I want to accomplish the same thing with queryset results
Users in database = {Steve, Chris, Jame, Cole, Casper, Courtney}
Query will filter the names that start with c
result = {Chris, COle, Casper, Courtney}
After I get the results, I want to select Casper from the results...
is there a way to do it like an array.
something like results[2]
UPDATE
So I have the part of the view working that will specify a specific record.
My only other question is to see if it is possible to do the same thing in the HTML tempalte file... Here is what I have in the view and html file. is there a way to do the same thing ht ehtml file...
view.py
i=0
for form in formset:
cd = form.cleaned_data
currentAmount = cd['amount']
currentDescription = cd['description']
print(currentAmount)
print(currentDescription)
currentTrans = transactions[i]
currentTrans.amount = currentAmount
currentTrans.description = currentDescription
currentTrans.save()
print(currentTrans)
i = i + 1
html
<form action="." method="POST">
{% csrf_token %}
{{ SplitFormSet.management_form }}
{% for form in SplitFormSet %}
{{ form.as_p }}
{% endfor %}
<p>Tax: <input type="text" name="tax" value=""></p>
<p>Tip: <input type="text" name="tip" value=""></p>
<input type="submit" name="submit" value="submit">
</form>
I tried this but it game me an error becuase 'i' is not a tag
<form action="." method="POST">
{% csrf_token %}
{{ SplitFormSet.management_form }}
{% i = 0 %}
{% for form in SplitFormSet %}
{{ transactions[i] }}
{{ form.as_p }}
{% i = i + 1 %}
{% endfor %}
<p>Tax: <input type="text" name="tax" value=""></p>
<p>Tip: <input type="text" name="tip" value=""></p>
<input type="submit" name="submit" value="submit">
</form>
names=Model.objects.filter(name__istartswith='c')
print(names[2])
In place of name you have put the field name of you model
I'm getting this error:
Exception Type: AttributeError
Exception Value:
'function' object has no attribute 'objects'
web/views.py in consultarE, line 153
from this:
views.py
def consultarE(request):
query = request.GET.get('q', '')
if query:
qset = (
Q(nombres__icontains=query) |
Q(apellidos__icontains=query) |
Q(telefono__icontains=query)
# Q(cargo__icontains=query)
)
results = Empleado.objects.filter(qset).distinct()
else:
results = []
return render_to_response("web/consultarEmpleado.html", {
"results": results,
"query": query
})
urls.py
url(r'^consultarEmpleado/$','consultarE',name='consultarEmpleado'),
consultarEmpleado.html
{% block content%}
<h1>Ingrese su búsqueda</h1>
<form class="navbar-form" role="search" action="." method="GET">
{{form|crispy}}
<label for="q">Buscar: </label>
<div class="input-group">
<input type="text" class="form-control" placeholder="Search" name="q" value="{{ query|escape }}">
<div class="input-group-btn">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
</div>
</div>
</form>
{% if query %}
<h2>Results for "{{ query|escape }}":</h2>
{% if results %}
<ul>
{% for empleado in results %}
<li>{{ empleado|escape }}</l1>
{% endfor %}
</ul>
{% else %}
<p>No se encontró empleado</p>
{% endif %}
{% endif %}
{%endblock%}
Check if there's a function called Empleado which overwrite reference to Empleado model.
def Empleado(...):
....
Adjust the function name not to conflict with the model name.
I can't understand, why this code is not work:
{% set t_c = 'param_1' %}
<div class="col-sm-9">
<select id="category" name="category" class="form-control " required>
<option></option>
{% for c in categories %}
{% if c.id|string == org.category.id %}
{% set t_c = 'param9' %}
<option value="{{ c.id }}" selected>{{ c.name }} </option>
{% else %}
<option value="{{ c.id }}">{{ c.name }} </option>
{% endif %}
{% endfor %}
</select>
</div>
<input id="category_h" name="category_h" type="hidden" value="{{ t_c }}">
Why t_c in last line is 'param_1', when condition {% if c.id|string == org.category.id %} is true?
Thanks.
UPDATE
I have fast solution on JavaScript with jQuery+Select2 like:
var category = $("#category"),
category_h = $("#category_h");
category.select2();
category_h.val(category.find("option:selected").text());
t_c = 'param9' is local to the scope of the for loop
There are workarounds to extend beyond inner block scope