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.
Related
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!
I want to render list of all objects on my template, for which their author is the currently logged in user. I passed the username of current user to url.py:
My List
My urls.py:
path('myscenarios/<str:username>/', MyScenarioListView.as_view(), name='myscenarios'),
My question is how to build the queryset in views.py and what to type in template block in my html?
class MyScenarioListView(LoginRequiredMixin, ListView):
model = Scenario
template_name = 'testmanager/myscenarios.html'
context_object_name = 'myscenarios'
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Scenario.objects.filter(scenarioAuthor = user).order_by('-date_posted')
What code should I type in my myscenarios.html file?
I want to render list of all objects on my template, which their author is current logged user.
Then you should not encode the user in the path, since a "hacker" can then simply change the URL to see the items belonging to a different user.
You can make use of self.request.user here. The path thus looks like:
path('myscenarios/', MyScenarioListView.as_view(), name='myscenarios'),
and in the view, we use:
class MyScenarioListView(LoginRequiredMixin, ListView):
model = Scenario
template_name = 'testmanager/myscenarios.html'
context_object_name = 'myscenarios'
def get_queryset(self):
return Scenario.objects.filter(
scenarioAuthor=self.request.user
).order_by('-date_posted')
It will pass the Scenarios as myscenarios to the template, so you can render this with:
{% for scenario in myscenarios %}
{{ scenario }}
{% endfor %}
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.
I'm fairly new to Django. I'm writing an app that displays articles using RSS. I want users to be able to react to any given article.
On the index, I display the latest articles dynamically (they are not stored in the DB).
View :
class IndexView(generic.ListView):
template_name = 'publisher/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView,self).get_context_data(**kwargs)
feeds = feedparser.parse('http://www.foo.com/rss/news.xml')
context['feeds'] = feeds
return context
Template :
{% for entry in feeds.entries %}
<li>
<a target="_blank" href="{{entry.link}}">{{entry.title}}</a>
I want to react
</li>
{% endfor %}
This works so far. I have a link next to each of these articles that should call the RSSReactView and display the article title, abstract, and a form to react. I don't want the article to be saved anywhere if the reaction is not posted, and thus I don't want any parameter to be included in the URL of the reaction form.
URL :
app_name = 'publisher'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^new_rss/react/$', views.RSSReactView.as_view(), name='rss_react'),
]
View :
class RSSReactView(generic.CreateView):
model = ReactionArticle
form_class = ReactionForm
template_name = 'publisher/react.html'
def get_context_data(self, **kwargs):
context = super(ReactView,self).get_context_data(**kwargs)
entry = self.kwargs['entry']
context['entry'] = entry
return context
def form_valid(self, form):
pass
Template :
<h1>You are reacting to article {{ entry.title }}</h1>
<p>
{{ entry.description }}
</p>
Of course, I get a NoReverseMatch error since the URL pattern isn't built to catch anything.
Passing parameters from DB stored objects through the URL is straightforward, but how do I pass a context variable ('entry', in this case) as an object to another view without using the URL ?
NB : I'm aware of the solutions using sessions or posts, but I can't believe that's the only way of doing it.
I'd like to have a button in many different Django templates that encourages users to subscribe to one of two dj-stripe paid plans, but I don't want to show the button to users who have already subscribed to either plan.
I know I can use {% if user.is_authenticated %} in templates. I haven't been able to find something similar for checking if a user is subscribed to a dj-stripe plan. Is there something, and if so, what is it? If not, how can I handle this without a lot of repetition?
It turns out that there is a dj-stripe solution to this already (that I hadn't found in my Google searches).
I just added this to my extended user model:
def __str__(self):
return self.username
def __unicode__(self):
return self.username
#cached_property
def has_active_subscription(self):
"""Checks if a user has an active subscription."""
return subscriber_has_active_subscription(self)
And then added this to my template:
{% if request.user.has_active_subscription %}
Subscription History
{% else %}
Upgrade to Premium Content!
{% endif %}
I agree with #nnaelle that adding an is_subscribed attribute to your user model is a good option for ensuring that the subscribe button isn't shown to your users that are already subscribed. Adding this attribute means that, if you haven't already, you'll need to extend the user model in your models.py to keep track of whether they are subscribed. This looks something like this (as in the Django docs):
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
is_subscribed = models.BooleanField(default=False)
The new user model can then be accessed by, say, the views in views.py:
from my_app.models import UserProfile
def index(request):
user = request.user
userprofile = UserProfile.objects.get(user=user)
...
You can (and might want to) avoid having to access the user profile that way, however, by making your new user model the default for your app under settings.py as described in the docs for substituting custom user models. Then after passing in the new user model to the view, you can do a check for subscription status using {% if not userprofile.is_subscribed %} and only show the subscription button for those who aren't subscribed:
{% if not userprofile.is_subscribed %}
<div ...></div>
{% endif %}
Feel free to give me your feedback!