I have read docs and other things, tried many tuts but still no luck. What I am trying to achieve is to show a custom error message.
I have this: /?message=success
And want to access this data in my Django template
class mysite(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(mysite, self).get_context_data(**kwargs)
return context
def get(self, request, *args, **kwargs):
return super(mysite, self).get(request, *args, **kwargs)
How I am accessing it in my template file:
{{ message }}
This gives no output. What I need is success to be read. Then I will do a conditional block on its base.
You can add message to the template context by changing your get_context_data method to
def get_context_data(self, **kwargs):
context = super(mysite, self).get_context_data(**kwargs)
context['message'] = self.request.GET.get('message', '') # default to empty string if not in GET data
return context
Then access message in your template with:
{{ message }}
Alternatively, make sure you are using the request template context processor, to make the request object available in your templates.
Then in your template, you can access the GET data with:
{{ request.GET }}
and the message parameter with:
{{ request.GET.message }}
Related
I am trying to override get_context_data() in a child class-based view to send more contextual data to the template, but it doesn't work. As a sample I am sending a test variable, but it is not rendered in the template.
class ProductList(LoginRequiredMixin, View):
template_name = 'product/product_scroll.html'
def get(self, request, *args, **kwargs):
#...
return render(request, self.template_name, data)
class Feed(ProductList):
template_name = "product/feed.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['test'] = 'sometestinfo'
return context
But in the template:
<p> Prueba: {{test}} </p>
is empty.
It's not working because you override get. Therefore the whole built in functionality of the view - including calling get_context_data - is bypassed. You almost never need to define the get or post methods.
I am listing data from a search result matching the name parameter of my Model. For each result I have a link to the detail page with the key parameter (which is a string) passed in the url, Like this
<ul>
{% for x in results %}
<li><a href = 'login/index/{{x.key}}'>{{x.name}}</a></li>
{% endfor %}
</ul>
My url.py looks like this
app_name = 'kpi'
urlpatterns = [
path('login/index/search', views.SearchView.as_view(), name="search"),
path('login/index/<slug:key>', views.EpicDetailView.as_view(), name="detail")
]
And my views.py look like this:
class SearchView(LoginRequiredMixin, TemplateView):
template_name = 'KPI/search.html'
def get(self, request, *args, **kwargs):
self.q = request.GET.get('q','')
self.results = Epic.objects.filter(name__icontains= self.q)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(SearchView, self).get_context_data(**kwargs)
context['results'] = self.results
return context
class EpicDetailView(LoginRequiredMixin, TemplateView):
template_name = 'KPI/epic_detail.html'
def get_context_data(self, **kwargs):
context = super(EpicDetailView, self).get_context_data(**kwargs)
context['lone_epic2'] = Epic.objects.get(key=self.kwargs['key'])
I know I am missing a step here, probably how i created the url path, or needing logic in my views. With the code above i get a page not found error because the template view link doesn't recoginze/match the EpicDetailView url
What I'm Trying to Accomplish
The purpose is to be able to click on the search result, push the key to the url, and store that key value as a variable to use in the EpicDetailView page
NOTE: Although I'm not showing it in the code above, my detail view will be displaying data from multiple model querysets so that is why i'm using TemplateView instead of DetailView for my EpicDetailView
You should pass the slug into your URL like so in your template:
<li>{{x.name}}</li>
Make sure that kpi is properly registered as the namespace for your KPI app. More info on the URL dispatcher here: https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#url
First off, sorry if I am not clear on what I'm trying to do or if I don't give enough info, I'm still relatively new to Django/Python.
I currently have a view that renders something like a blog post:
class SingleCharacter(LoginRequiredMixin,generic.DetailView):
model = models.Character
def get_context_data(self, **kwargs):
context = super(SingleCharacter, self).get_context_data(**kwargs)
return context
And, in the template for this view, I have a template tag that checks if the user is authenticated AND the owner of the post:
{% if user.is_authenticated and user == character.user %}
However, I'm currently in the process of incorporating xhtml2pdf into my project and this method of securing the post to only the user who created it is causing some issues.
I'm wondering if it's possible to move the user.is_authenticated and user == character.user into the view instead of a template tag, and if so can i do it with a simple if statment, something like this?
class SingleCharacter(LoginRequiredMixin,generic.DetailView):
model = models.Character
if user.is_authenticated and user == character.user:
def get_context_data(self, **kwargs):
context = super(SingleCharacter, self).get_context_data(**kwargs)
return context
else:
<I'll include some redirect to a 404 page>
I'm trying to see if there's another way to do it, but I thought I'd throw this out here to the more experienced people in hopes of figuring it out.
Thanks for any help!
You can override the get method of the DetailView and handle the logic there:
class SingleCharacter(LoginRequiredMixin,generic.DetailView):
model = models.Character
def get(self, request, *args, **kwargs):
self.object = self.get_object()
if self.request.user.is_authenticated and self.request.user == self.object.user:
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
else:
# redirect
I have created a Class view in views.py of the django application.
class HelloTemplate(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(HelloTemplate, self).get_context_data(**kwargs)
return context
Now I have a form defined in the html page:
<form method="get">
<input type="text" name="q">
<input type="text" name="q1">
<input type="submit" value="Search">
</form>
As you can see, I am submitting the form on the same page.
Now I want to get the form submitted values in my HelloTemplate class. I don't want to create another class or methods outside the existing class.
Also, I would like to send an error message to the html form if data is not validated in the django.
I don't know how to do this, please help me out.
You need to define get (because your form defined with get method <form method="get">) method in view class:
class HelloTemplate(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(HelloTemplate, self).get_context_data(**kwargs)
return context
def get(self, request, *args, **kwargs):
q = request.GET.get('q')
error = ''
if not q:
error = "error message"
return render(request, self.template_name, {'error': error})
More information in django docs here Introduction to Class-based views
There's only one value, and it's in request.GET['q'].
Quick response, I can show you what I did a while ago for a review form (for people to create a new review, one of my models):
def review_form_view(request):
c = {}
c.update(csrf(request))
a = Review()
if request.method == 'POST':
review_form = Review_Form(request.POST, instance=a)
if review_form.is_valid():
a = review_form.save()
return HttpResponseRedirect('../dest_form_complete')
pass
else:
review_form = Review_Form(instance=a)
return render_to_response('../review_form.html', {
'review_form': review_form,
}, context_instance=RequestContext(request))
If you have a user model, comment model, etc. you can probably use something similar to this. Very (very) roughly put, the request is the input that the user fills out in the form, 'POST' is the method called that lets the server know you are adding entries to your database, and is_valid() validates the data according to your models.py parameters (can name be NULL? Is age an integer? etc).
Take a look at https://docs.djangoproject.com/en/dev/topics/forms/ as well for more examples and explanation.
I am using Django DeleteView in a template and I've created a url & view.
Is it possible to skip the process of loading the _confirm_delete template and just post the delete immediately.
DeleteView responds to POST and GETÂ requests, GET request display confirmation template, while POST deletes instance.
You can send POST request, without confirmation with form like this:
<form method="POST" action="{% url "your_delete_url_name" %}">
{% csrf_token %}<input type="submit" value="DELETE">
</form>
If you do not want to have a link instead form button, use some javascript to make invisible form, that will be submitted on link click.
It is not good practice to use GET request for updating or deleting, but if you really insist you can shortcut get method in your class view to post, ie:
def get(self, *args, **kwargs):
return self.post(*args, **kwargs)
Or you can redefine get() method in your DeleteView:
class YourDeleteView(DeleteView):
model = YourModel
success_url = '<success_url>'
def get(self, request, *args, **kwargs):
return self.post(request, *args, **kwargs)
But be careful with that, ensure that this doesn't affect other functionality.
Yes, just change the next parameter. In your return response, make sure that the dictionary that you pass in is has something like this : { 'next': '/<your_path_here>}/' }, make sure you commit the changes before adding the next parameter. You might want to change your view's get and post functions.
Or you could only allow HTTP request method delete by routing the request directly to the delete method of your class.
from django.views.generic import DeleteView
from django.http import HttpResponseForbidden
class PostDeleteView(DeleteView):
model = Post
http_method_names = ['delete']
def dispatch(self, request, *args, **kwargs):
# safety checks go here ex: is user allowed to delete?
if request.user.username != kwargs['username']:
return HttpResponseForbidden()
else:
handler = getattr(self, 'delete')
return handler(request, *args, **kwargs)
def get_success_url(self):
username = self.kwargs.get('username')
success_url = str(reverse_lazy('post:user_home', kwargs={'username': username}))
return success_url
Let's say your URL looks like this:
path('posts/delete/<int:pk>/', PostDeleteView.as_view(), name='post_delete'),
For clarity why this works, you have to analyze the post and delete methods.
def post(self, request, *args, **kwargs):
return self.delete(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
"""
Call the delete() method on the fetched object and then redirect to the
success URL.
"""
self.object = self.get_object()
success_url = self.get_success_url()
self.object.delete()
return HttpResponseRedirect(success_url)
post just calls delete and delete gets the object and success URL, deletes the object, then redirects to the success URL you provided. pk_url_kwarg = 'pk' is why I showed the <int:pk> part in the URL.
You can override the get() method to behave exactly like the delete() method:
def get(self, request, *args, **kwargs):
return self.delete(request, *args, **kwargs)
See CCBV here: https://ccbv.co.uk/projects/Django/4.1/django.views.generic.edit/DeleteView/
All you have to do is override the get_success_url method of your delete view. Then it will directly delete the object from the DB. Eg:
class YourView(DeleteView):
model = YourModel
def get_success_url(self):
return reverse('your_redirect_view')