Can someone help me figure out why my Django template pages won't render anything?
I'm using Python Requests (http://docs.python-requests.org/en/latest/) to retrieve JSON data from the external urls. I decode the data by using .json(). This works as I would expect when executing this from command line, but when it does nothing in the view.
When I run the server, the page is blank. It has no title, no 'testing' printed, nothing.
My Template:
<html>
<head><title>Offer List</title></head>
<body>
<p>Testing</p>
{% load dictparser %}
{% for offers in network1_offers %}
{% autoescape off %}
<div>
<p>name: {{ offers|lookup:"name" }}</p>
<p>pay: {{ offers|lookup:"payout" }}</p>
<p>description: {{ offers|lookup:"description" }}</p>
</div>
{% empty %}
<li>Sorry, no surveys available.</li>
{% endautoescape %}
{% endfor %}
</body>
</html>
My View:
class OffersList(View):
template_name="generic_app/offers.html"
def load_offers(request):
"""
import example network offers.
"""
user = request.user
user_agent = request.META['HTTP_USER_AGENT']
amparams = {'user_subid':user.sub_id, 'useragent':user_agent, 'user_ip':user.ip_address}
examplenetwork = requests.get('http://example.com/api-get.php?pubid=00000&key=000000000000&mode=offers&incent=1', data=amparams)
exampleoffers= examplenetwork.json()
"""
import example network 2 offers.
"""
clparams = {'subid':user.sub_id, 'ua':user_agent, 'geoip':user.ip_address}
examplenetwork2 = requests.get('http://www.examplenetwork2.com/blahblah', data=clparams)
exampleoffers2 = examplenetwork2.json()
render(request, 'generic_app/offers.html', {'network1_offers':exampleoffers, 'network2_offers':exampleoffers2})
The url:
url(r'^dashboard/offers$', OffersList.as_view(), name="offers"),
You're seeing this because you haven't defined how to get to the load_offers() method in your view, currently your load_offers() method is just a method floating around in your class.
Using the base class View comes with it's methods that you need to implement, for example
class OfferView(View):
template_name = "generic_app/offers.html"
def get(self, request, *args, **kwargs):
return load_offers(request)
or much better change this to a TemplateView(because that's what it really is).
class OfferView(TemplateView):
template_name = "generic_app/offers.html"
def get_context_data(self, **kwargs):
context = super(OfferView, self).get_context_data(**kwargs)
context['offers'] = load_offers(self.request)
return context
Related
Disclaimer: I am aware of several other posts that raise my issue, but they do not apply to my code.
Hi everyone, I am creating a knockoff of stackoverflow using Django, and I came into an issue.
I have a View that shows a question that has been asked. Obviously, anyone coming to that question should be able to answer it. Here are the views and templates:
This view displays the question and some other info:
class QuestionsDetailView(DetailView):
model = Question
template_name = "function/questions/questions_detail.html"
def get_context_data(self, *args, **kwargs):
context = {}
question_detail = Question.objects.filter(id=self.kwargs.get("pk")).first()
answers = Answer.objects.filter(question=question_detail)
context["question"] = question_detail
context["questioncomments"] = QuestionComment.objects.filter(question=question_detail)
context["answers"] = [[answer, AnswerComment.objects.filter(answer=answer)] for answer in answers]
return context
This view allows you to answer:
class AnswersCreateView(LoginRequiredMixin, CreateView):
model = Answer
fields = ["content"]
template_name = "function/answers/answers_create.html"
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse("function-questions-detail", kwargs={"pk": self.kwargs.get("pk")})
On stackoverflow, when you view a question, you can answer it by scrolling down and providing your answer. I wanted to do something similar, so instead of having the answer view on a separate page, I put in in the question detail page using the 'include' template tag. Here are the templates:
This is the template for the question (which contains the include statement (bottom)):
{% extends 'core/base.html' %}
{% block content %}
<!--Question-->
<h1>{{ question.title }} by {{ question.author }}</h1>
{% if user == question.author %}
Update
Delete
{% endif %}
<h3>{{ question.content }}</h3>
<!--QuestionComments-->
{% for comment in questioncomments %}
<h6>{{ comment }} -- {{ comment.author }}</h6>
{% endfor %}
<!--Answers-->
{% if answers %}
{% for pair in answers %}
<!--Answers-->
<h3>{{ pair.0.content }}</h3>
<h5>{{ pair.0.author }}</h5>
<!--AnswerComments-->
{% for comment in pair.1 %}
<h6>{{ comment }}</h6>
{% endfor %}
{% endfor %}
{% endif %}
{% include 'function/answers/answers_create.html' %}
{% endblock content %}
Here is the template for the form which allows you to create an answer (this is the template that is referenced by the include template tag):
{% load crispy_forms_tags %}
<form method="POST">
{% csrf_token %}
<h2>Your Answer</h2>
{{ form|crispy }}
<button type="submit">Submit</button>
</form>
When I tried it out on the website in a browser, the question was rendering but the answer form was rendering everything except the form fields. It is rendering 'Your Answer' and the submit button but it is not rendering the actual field.
When I press submit I get the following error in my command prompt:
Method Not Allowed (POST): /questions/3/
Method Not Allowed: /questions/3/
So, in actual fact, the problem is how do I render the form properly. And will that solve the issue?
Thanks in advance.
Use form and pass it through context in your DetailView.
#form
class AnswerCreateForm(forms.ModelForm):
class Meta:
fields = ['content']
#views
class QuestionsDetailView(DetailView):
.......
def get_context_data(self, *args, **kwargs):
......
context['form'] = AnswerCreateForm()
return context
# create view
# provide same template name as the detail view.
class AnswersCreateView(LoginRequiredMixin, CreateView):
model = Answer
form_class = AnswerCreateForm
template_name = "function/questions/question_detail.html"
I have a detail view that uses a Quiz object to display data stored in that object, like title and author. I want to have a button that links to a new page that displays different data from the same object. I don't know how to pass this data/object.
I can render the view and pass it the context of a specific quiz using an id but I want the id to change to be the id of the object from the initial page.
#assessement view
def assessment(request):
context = {
'quiz':Quiz.objects.get(id=1),
}
return render(request, 'quiz_app/assessment.html', context)
#detailview template for quiz
{% extends "quiz_app/base.html" %}
{% block content %}
<article class="quiz-detail">
<h1>{{ object.title }}</h1>
<h2>{{ object.question_amount }} Questions</h2>
<a class="btn" href="{% url 'quiz-assessment' %}">Start Quiz</a>
</article>
{% endblock content %}
#assessment template
{% extends "quiz_app/base.html" %}
{% block content %}
<h2>Assessment</h2>
<h2>Title is {{ quiz.title }}</h2>
{% endblock content %}
Then you should make another view for url quiz-assessment and pass the quiz pk as you did above in your assessment view.
def quiz_assessment(request,pk):
quiz = Quiz.objects.get (pk=pk)
return render (request,'assessment_template', {'quiz':quiz}
And in your url,pass the quiz id like this:
path ('<int:pk>/quiz/assessment /',views.quiz_assessment,name='quiz_assessment')
And in your template you can give url like this:
< a class="btn" href="{% url 'quiz_assessment' object.pk %}>
As suggested in the comments by #Robin Zigmond, you can do like this.
#assessement view
def assessment(request, qid):
context = {
'quiz':Quiz.objects.get(id=qid),
}
return render(request, 'quiz_app/assessment.html', context)
In the HTML file
#detailview template for quiz
{% extends "quiz_app/base.html" %}
{% block content %}
<article class="quiz-detail">
<h1>{{ object.title }}</h1>
<h2>{{ object.question_amount }} Questions</h2>
<a class="btn" href="{% url 'quiz-assessment' qid=object.id %}">Start Quiz</a>
</article>
{% endblock content %}
and in your urls.py change as:
path('quiz_asswssment/?P<int:qid>/', views.assessment, name="quiz_assessment")
Besides, what SammyJ has suggested, You can use the django sessions library or the django cache framework. You can temporarily store the information you need for the next view and access it whenever you want to.
In what Sammy J had suggested, you will always to have make sure that the queryset is passed in the context, otherwise it will not be rendered.
def assesment(self, request, id):
q = Quiz.objects.get(pk=id)
request.session["someData"] = q.name
request.session["qAmount] = q.amount
In your template file
<p>The title is : {{request.session.title}} and the amount is {{request.session.qamount}}
Note: Django sessions do not allow you to set a queryset as a session record, for that, you can use Django Cache framework.
Example
from django.core.cache import cache
cache.set('quiz', q)
getting cache -> cache.get('quiz')
Sessions framework docs : https://docs.djangoproject.com/en/2.2/topics/http/sessions/
Cache framework docs: https://docs.djangoproject.com/en/2.2/topics/cache/
I want to loop data taken from database in rendered template. Using cms plugin.
I dont have problem looping data in html template. But if i use CMSPlugin to insert new app in placeholder, nothing shows.
If i run url localhost:port/test.html.I got input what i want. But rendered template doesnt loop data.
{% for post in posts %}
{{ post.firstoption }}
{% endfor %}
if I use code below, nothing shows in my rendered template. Values are passed in rendered template. Because, if i try {{instance.firstoption}} i get value shown in template. Problem is i cant loop data with tag instance.
{% for post in instance.posts %}
{{ post.firstoption }}
{% endfor %}
I also tried {% for post in instance.posts_set.all %}
and {% for post in instance.posts.all %}
cms_plugins.py
class pricing(CMSPluginBase):
model = mymodel
name = _("myplugin")
render_template = "template.html"
cache = False
def render(self, context, instance, placeholder):
context.update({'instance': instance})
return context
models.py
class mymodel(CMSPlugin):
firstoption = models.CharField(max_length=200)
def __str__(self):
return self.firstoption
It is probably because you need to call all on your posts
{% for post in instance.posts.all %}
{{ post.firstoption }}
{% endfor }
I'm following a tutorial on effectivedjango.com, and this is the code they have:
views.py:
class CreateContactView(CreateView):
model = Contact
template_name = 'edit_contact.html'
fields = '__all__' #this is needed for error msg Using ModelFormMixin (base class of CreateContactView) without the 'fields' attribute is prohibited.
def get_success_url(self):
return reverse('contacts-list')
def get_context_data(self, **kwargs):
context = super(CreateContactView, self).get_context_data(**kwargs)
context['action'] = reverse('contacts-new')
return context
class UpdateContactView(UpdateView):
model = Contact
template_name = 'edit_contact.html'
fields = '__all__'
def get_success_url(self):
return reverse('contacts-list')
def get_context_data(self, **kwargs):
context = super(UpdateContactView, self).get_context_data(**kwargs)
context['action'] = reverse('contacts-edit', kwargs={'pk' : self.get_object().id})
return context
urls.py:
url(r'^$', contacts.views.ListContactView.as_view(),
name='contacts-list',),
url(r'^new$', contacts.views.CreateContactView.as_view(),
name='contacts-new',),
url(r'^edit/(?P<pk>\d+)/$', contacts.views.UpdateContactView.as_view(),
name='contacts-edit',),
contact_list.html:
{% block content %}
<h1>Contacts</h1>
<ul>
{% for contact in object_list %}
<li class="contact">
{{ contact }}
(edit)
</li>
{% endfor %}
</ul>
Add contact
{% endblock %}
edit_contact.html:
{% block content %}
{% if contact.id %}
<h1>Edit Contact</h1>
{% else %}
<h1>Add Contact</h1>
{% endif %}
<form action="{{ action }}" method="POST">
{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input id="save_contact" type="submit" value="Save" />
</form>
Back to list
{% if contact.id %}
Delete
{% endif %}
{% endblock %}
Why does the line context['action'] = reverse('contacts-edit', kwargs={'pk' : self.get_object().id}) in views.py look like its calling itself?
What I mean is, this action is called when the submit button is pressed in the contact-edit template, correct? So it starts there, and it is reverse-calling contact-edit which is itself, right?
What am I not seeing here?
Thank you for all your help.
Yes, the line context['action'] = reverse('contacts-edit', kwargs={'pk' : self.get_object().id}) in views.py is calling itself. This line generates the proper url for contacts-edit view.
This is done so that POST requests come to the same view i.e. UpdateContactView which is an UpdateView. There, proper handling will be done i.e. form validation will occur with the sent data. If the form is valid, object will be updated. Otherwise, the form will be displayed again with errors.
Django docs on UpdateView:
A view that displays a form for editing an existing object,
redisplaying the form with validation errors (if there are any) and
saving changes to the object.
I've made a simple template tag to list child pages in a django-cms site.
It's working fine except for the fact that I have not been able to render the child pages placeholders in the template tag itself.
The following is my code for the template tag.
subpages.py
from cms.models import Page
from cms.utils.page_resolver import get_page_from_path
from django import template
register = template.Library()
#register.inclusion_tag('subpages.html', takes_context = True)
def get_news_items( context ):
request = context['request']
subpages = request.current_page.children.filter(published=True)
return {'subpages':subpages}
subpages.html
{% load cms_tags menu_tags placeholder_tags %}
<ul>
{% for item in subpages %}
<li>{{ item.get_title }}
{% render_placeholder subtitle %}
</li>
{% endfor %}
</ul>
I've tried some alternatives to *render_placeholder* but without luck.
How would be the correct way to get the placeholder rendered?
This is only a (untested) suggestion, but try passing the context along to the template:
#register.inclusion_tag('subpages.html', takes_context = True)
def get_news_items( context ):
request = context['request']
subpages = request.current_page.children.filter(published=True)
context.update({'subpages':subpages})
return context