In django, how generic view works - python

I have started learning django, I'm not sure how generic view works. I read django documentation several times, I can't gain clear understanding of how generic view works. Very strange but it works well. It retrieves data from the database and renders data on the browser.
Here is snippet code of polls/urls.py.
url(r'^$', views.IndexView.as_view(), name = 'index')
It will go to the IndexView class in views.py.
Here is snippet code of polls/views.py.
from django.views import generic
from .models import Question, Choice
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Question.objects.order_by('-pub_date')[:5]
When I change template_name as something, the exception has occurred as follows.
TemplateDoesNotExist: polls/question_list.html
What does question_list.html mean?
Where does it come from?
And here is index.html.
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>
{{ question.question_text }}
</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
As you can see, index.html file use latest_question_list as a parameter but I'm not sure how can the latest_question_list be used.
In views.py file, what does context_object_name = 'latest_question_list' mean?
Where does the 'latest_question_list' come from and how can index.html use latest_question_list?
Do I use context_object_name in views.py?
What's the role of the get_queryset() function?

What does question_list.html mean?
It means that there is a file inside polls dir like index.html
if you want to have a file with a diff name you have to change the name of template_name='polls/name_of_file_inside_polls'
Do I use context_object_name in views.py?
The context is the place where you put some vars to use it in your templates, that's why you can use latest_question_list
What's the role of the get_queryset() function?
It creates the query that is passed to the template.

I understand what they mean.
By default, the DetailView generic view uses a template called /_detail.html. In my case, it would use the template "polls/question_detail.html". The template_name attribute is used to tell Django to use a specific template name instead of the autogenerated default template name. I also specify the template_name for the results list view – this ensures that the results view and the detail view have a different appearance when rendered, even though they’re both a DetailView behind the scenes.
For DetailView the question variable is provided automatically – since we’re using a Django model (Question), Django is able to determine an appropriate name for the context variable. However, for ListView, the automatically generated context variable is question_list. To override this we provide the context_object_name attribute, specifying that we want to use latest_question_list instead.

Related

How can I delete the answers (code in body)?

I am creating a Q&A website for practice, I created the answer and the question model and linked them together, however I can not access the template that I set for the deletion of the answer model, I created a DeleteView to delete the question. Here is the code:
views.py:
class Politics_post_details(DeleteView):
model = PoliticsPost
context_object_name = 'politicsposts'
pk_url_kwarg = 'qid'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# now you can get any additional information you want from other models
question = get_object_or_404(PoliticsPost, pk=self.kwargs.get('qid'))
context['answers'] = Answer.objects.filter(post=question).order_by('-date_posted')
return context
class AnswerDelete(UserPassesTestMixin,DetailView):
model = Answer
success_url = reverse_lazy('Lisk home')
pk_url_kwarg = 'aid'
def test_func(self):
answer = self.get_object()
if self.request.user ==answer.author:
return True
return False
urls.py(not root):
path('politicspost/<int:qid>/createanswer/',views.CreateAnswer.as_view(template_name='lisk_templates/createanswer.html'),name = 'Answer'),
path('politicspost/<int:qid>/answer/<int:aid>/delete/',views.AnswerDelete.as_view(template_name = 'lisk_templates/answer_delete.html'),name='Answer_Delete'),
path('politicspost/<int:qid>/',views.Politics_post_details.as_view(template_name='lisk_templates/politics_post_details.html'),
I created the template but whenever I try to access it, it gives me an error as follows:
NoReverseMatch at /politicspost/29/
Reverse for 'Answer_Delete' with arguments '(36,)' not found. 1 pattern(s) tried: ['politicspost/(?P<qid>[0-9]+)/answer/(?P<aid>[0-9]+)/delete/$']
Thanks in advance.
answer_delete.html:
{%extends "lisk_templates/base.html"%}
{% block title %}
Page title
{% endblock title %}
{% block body%}
<div class="feed" style="background-color:lightred;"><form method="POST">
{% csrf_token %}
<h3>Are you sure that you want to delete this answer: <br>
{{ object.content }}</h3>
<button id="signin" type="submit">Yes</button> No
</form>
</div>
{% endblock body %}
You have a number of issues. The biggest one is that you have switched DeleteView and DetailView (your DeleteView is a DetailView and vice versa).
And then you should either rename your template to answer_confirm_delete or add the template_name_suffix to your DeleteView. See the documentation for further details:
https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-editing/#django.views.generic.edit.DeleteView
If you use Django's DeleteView, you don't need to specify a url in the template, it will do all the work for you. Just make sure you specify the url correctly in your urls.py. Fix these issues and see if it works then.
May Be This Might Work For You, Because You Never Used The Import Of DeleteView
from django.views.generic import DeleteView
"""This Is From My Blog App, That I Used For My Blog App, Hope This Will Help"""
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
success_url = reverse_lazy('post_list')
Happy Coding, let me know if there are any issues with this I'am Up for you!

Method get_context_data is called twice when using template tags in django

I have a template_tag.py:
from django import template
from myapp.views import RenderView
register = template.Library()
#register.inclusion_tag("template_tag.html")
def render_myapp():
rv=RenderView()
return rv.get_context_data()
and myapp.views.py:
from django.views.generic.base import TemplateView
class RenderView(TemplateView):
template_name = "test.html"
def get_context_data(self, **kwargs):
context = super(RenderView, self).get_context_data(**kwargs)
context["test"] = 1 # this is hit twice in the debugger
return context
template_tag.html:
{% if test %}
{{ test|safe }}
{% endif %}
base.html (different app):
{% load template_tag %}
{% render_myapp %}
I wonder why RenderView().get_context_data() is hit twice in the debugger? I don't call it twice in my template. It's probably because TemplateView already calls get_context_data and then I call it again rv.get_context_data(). But then how should my template_tag.py look like to not call get_context_data() again?
There seem to be two situations here.
In one case, the template tag is always in a template that is rendered by your RenderView. In which case, there doesn't seem to be any need for a tag; you should just either include template_tag.html or put its code directly into test.html.
In the other case, the tag is in another template, or in a range of templates that may or may not be rendered by RenderView. In which case, why is the context data for that page defined in RenderView? It should be defined directly in render_myapp().

Override django change_form.html template when a third app is overriding it

I am trying to override change_form.html only for one model, so I did as explained in the django documentation and created /templates/my_app_name/my_model_name/change_form.html.
The problem is, it is not working and I am not seeing the extra features that I have added to the change_form template. I am using django_guardian, which also overrides the same template, so my assumption is that this is causing the issue. It is worth mentioning, that before placing the template in the my_app_name/my_model_name/ folder, the features of both templates were visible in the admin interface.
Is there a way to apply this only for 1 model?
You should check this answer.
You can specify which template to extend in your template.
So you're extending third app's template which extends djando admin's template.
Example:
admin.py
class MyModel(ThirdAppModelAdmin):
change_form_template = 'my_app_name/templates/change_form.html'
my_app_name/templates/change_form.html
{% extends "thirdapp/templates/change_form.html" %}
{% block thatYouNeed %}
{{ block.super }}
Your content here
{% endblock %}
Well, at least this is how I managed to do that.
The GuardedModelAdmin changes change_form_template to use the template from django-guardian. Try changing it back in your model admin class:
class MyModelAdmin(GuardedModelAdmin):
...
change_form_template = 'my_app_name/my_model_name/change_form.html'

Detail template in Django not taking values

from django.views import generic
from .models import Inspectionfile
from .models import posts
class IndexView(generic.ListView):
template_name = "posts/index.html"
def get_queryset(self):
return Inspectionfile.objects.all()
class DetailView(generic.DetailView):
model = Inspectionfile
template_name = "posts/detail.html "
#index template
<ul>
{% for o in object_list %}
<li>{{o.document_title}} </li>
{% endfor %}
</ul>
#detail template
<h1>{{ o.document_title }}</h1>
My Index template works but the detail template does not seem to take the value so just appears blank . So is the 'o' not being passed to detail ?? I have not been able to solve this. BTW document_title is one of the field of my inspectionfile model. I checked my url regex and it seems to work fine.
o is an object which only exists within the for loop in your list view template. It isn't passed anywhere.
The detail view has its own context; there the object that is identifued by the url argument is called just object.

Django's get_context_data function not working?

I'm practicing with Django's Class Based View.
It seems like my overridden get_context_data function is not working properly, but I have no idea what is wrong :(
My code:
urls.py
url(r'^user/(?P<pk>\d+)/posts/$', UserPosts.as_view(), name='user_post'),
views.py
class UserPosts(ListView):
template_name = 'app_blog/user_posts_page.html'
context_object_name = 'post_list'
def get_queryset(self):
self.user = get_object_or_404(User, id=self.kwargs['pk'])
return self.user.post_set.order_by('-id')
def get_context_data(self, **kwargs):
context = super(UserPosts, self).get_context_data(**kwargs)
context['user'] = self.user
return context
user_post_page.html
{% block content %}
<div class="main_content">
<h2>Welcome to {{user.username}}'s User Post Page!</he>
<ul>
{% for post in post_list %}
<li>{{post.post_title}}</li>
{% endfor %}
</ul>
</div>
{% endblock %}
The html page correctly displays the user's post_list, BUT the h2 tag displays:
Welcome to 's User Post Page!
I'm pretty sure I passed the 'user' variable in the get_context_data function, but the html page does not displa the user.username... Any idea why this is happening :(??
Thanks
Use another name that is not user. It seems like RequestContext overwrite user variable.
Please see the default TEMPLATE_CONTEXT_PROCESSORS, which set the django.contrib.auth.context_processors.auth.
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every RequestContext will contain these variables:
user – An auth.User instance representing the currently logged-in user (or an AnonymousUser instance, if the client isn’t logged in).
perms – An instance of django.contrib.auth.context_processors.PermWrapper, representing the permissions that the currently logged-in user has.
So you'd better give your user variable another name.
As the other answers said, don't use the variable name user. But even more importantly, in this particular case the ListView is not the best generic class to use; instead, you're better off using the DetailView, which makes your view much simpler:
class UserPosts(DetailView):
model = User
template_name = 'app_blog/user_posts_page.html'
context_object_name = 'listed_user'
The only change in your template is to use listed_user instead of the user variable. Since DetailView already looks into the pk URL argument, it will select and return the right User automatically.

Categories

Resources