How to pass the "render_to_response arguments" to an new view?
def show_list(request, id):
try:
profile = request.user.get_profile()
list = Lista.objects.get(user_profile = profile)
except Lista.DoesNotExist:
c = {}
c.update(csrf(request))
titlepage = "ooops, you don't have a list YET! click on button to create one!"
c = {'profile' : profile, 'request' : request, 'titlepage' : titlepage}
return render_to_response('/profiles/list/create/',c,context_instance=RequestContext(request))
with this last line this doesn't work, the url /profiles/list/create/ redirects to a view create_list.
Well, I know that I could write something like redirect(/profiles/list/create/) but with this I cannot pass the dictionary c.
Thanks in advance
You should use django.contrib.messages to display your message and redirect user to another view.
View code:
from django.contrib import messages
from django.shortcuts import redirect
def show_list(request, id):
try:
# normal flow
except Lista.DoesNotExist:
messages.warning("ooops, you don't have a list YET! click on button to create one!")
return redirect("/profiles/list/create/")
Somewhere in create template:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
Also remember to properly enable messages.
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
Related
I'm making a messaging system which has a message model and some views for things like inbox and conversation.
Inbox view and template works and is linked to the conversation through the id of the sender. However, when I click on the senders name (The senders name is the link (template link is {{ sender }}) that is meant to trigger the conversation view which is supposed to render the template convo.html ( the project level url for that is url(r'^messaging/inbox/conversation/(?P<id>[\w-]+)/$', message_views.Conversation.as_view(), name="conversation"),) ), Django changes the url but stays on the same page(So it triggers the inbox view and stays on inbox.html and changes the url but doesn't trigger the conversation view and doesn't render the convo.html template). I've tried changing from a function based view to a class based view and it did nothing. What am I doing wrong?
Note: I'm still new to django so forgive me for any bad practices; I'm attempting to teach myself.
views.py (inbox and conversation views)
def inbox(request):
messages = Message.objects.filter(receiver=request.user.id)
senders = {}
for message in messages:
if message.sender not in senders:
senders[message.sender] = message
return render(request, 'inbox.html', {'senders': senders})
# There is only ever one of this view, either the CBV or FBV
def conversation(request, other_user_id):
print(request.method)
if request.method == "POST":
reply = request.post['reply']
other_user = CustomUser.objects.get(id=other_user_id)
message = Message(sender=request.user, receiver=other_user)
message.save()
return redirect("conversation")
else:
other_user = CustomUser.objects.get(id=other_user_id)
messages = Message.objects.filter(Q(receiver=request.user) & Q(sender=other_user))
print(messages)
return render(request, 'convo.html', {'messages': messages})
# Class based conversation view
class Conversation(View):
def post(request, other_user_id):
reply = request.post['reply']
other_user = CustomUser.objects.get(id=other_user_id)
message = Message(sender=request.user, receiver=other_user)
message.save()
return redirect("conversation")
def get(request, other_user_id):
other_user = CustomUser.objects.get(id=other_user_id)
messages = Message.objects.filter(Q(receiver=request.user) & Q(sender=other_user))
print(messages)
return render(request, 'convo.html', {'messages': messages})
template - inbox.html
<!DOCTYPE html>
{% extends "accbase.html" %}
<!--Omitted outbox in favor of conversation-->
{% block content %}
<div class="inbox">
<h1>Inbox</h1>
<hr>
{% for sender in senders %}
{{ sender }}
<br>
{{sender.message.created_at}}
<br>
{% endfor %}
</div>
{% endblock %}
template - convo.html
<!DOCTYPE html>
<!--Template for reciever side of conversation-->
{% extends "accbase.html"%}
{% block content %}
<div class="conversation">
<h1>Conversation with {{sender}}</h1>
<p>
{% for msg in messages %}
<!--Order is descending ~~ bottom to top: newest to oldest-->
{{ msg.content }}
<br>
{% endfor %}
<hr>
<form method="POST">
<label>Reply</label>
<input type="text" name="reply">
</form>
</p>
<button type="submit">Send</button>
</div>
{% endblock %}
project level urls.py
from django.urls import path, re_path, include
from django.conf.urls import url
from messaging import views as message_views
urlpatterns = [
url(r'^messaging/inbox', message_views.inbox, name="inbox"),
url(r'^messaging/inbox/conversation/(?P<id>[\w-]+)/$', message_views.Conversation.as_view(), name="conversation"),
]
As Daniel Roseman said in comments " The problem here is that you didn't terminate the regex for your inbox URL, so it also matches the conversation URL. " so I added the needed $ to the end of the inbox url pattern and that fixed it!
I am creating an app when a user can search for recipes by inputing some ingredients in search-field.
I would like to do that when search-field is empty or string is empty a user get error.message 'Please put input.' But after i have implemented message.error into views and template it only returns the same page without this informaton 'Please put input.'. Do you know what i made wrong here?
My views:
from django.shortcuts import render
from django.db.models import Q #new
from .models import Recipe
from .models import Ingredient
from django.contrib import messages
from django.shortcuts import redirect
def drink_list(request):
template = "drinks/drink_list.html"
return render(request, template)
def search_results(besos):
query = besos.GET.get('q')
if not query or query == ' ' or query == ' ' or query == ' ':
messages.error(besos, "Please put input")
return redirect('drink_list')
else:
q = Q()
for queries in query.split():
q |= (Q(ingredients__ingredient_name__icontains=queries))
#why it look for 'sok z cytryny' and show as well sok z limonki
results = Recipe.objects.filter(q)
template = "drinks/search_results.html"
context = {
'results' : results,
}
return render(besos, template, context)
My template search_results:
{% if results %}
{% for drink in results %}
<div>
<p>{{ drink.recipe_name }}</p>
<p>Preparation: {{ drink.preparation }}</p>
<p>Ingredients:
{% for ingredient in drink.ingredients.all %}
{{ingredient.ingredient_name}}{% if not forloop.last %},{% endif %}
{% endfor %}
</p>
</div>
{% endfor %}
{% elif messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% else %}
<div>Such ingredients do not exist</div>
{% endif %}
If there is no query term , you are currently redirecting to:
return redirect('drink_list')
but you are not passing the message on to the drink_list view.
In case of redirect, you can pass the message string as argument
return redirect('{}?message=Please put input'.format(reverse('drink_list)))
Then your drink_list template must include:
<ul class="messages">
<li>{{ message }}</li>
</ul>
You need to further modify your drink_list function to get the message argument:
def drink_list(request):
template = "drinks/drink_list.html"
message = request.GET.get('message', ''))
return render(request, template, message=message)
And finally your url must include the optional message argument :
path('drink_list/', views.drink_list,name='drink_list'),
When i submits the form i want to pass message as "form successfully submitted" to the same page "successs.html".How it possible?
class SuccessView(FormView):
template_name = 'success.html'
form_class = QuestForm
success_url='success'
def form_valid(self, form):
ob9=Logs.objects.all()
for i in ob9:
logids=i.id
str(logids)
q1= form.cleaned_data['ques']
obj1=Quest.objects.create(logid=logids,status=0,question=q1)
return super(SuccessView,self).form_valid(form)
If you use Django's messages framework, it's as simple as adding a message at any point during the call processing (this adds the message to the current request object) and it will be added to the response:
from django.contrib import messages
messages.success("Form successfully submitted")
You can do this just before your call to return super().form_valid(form).
In your template you need to add the code to diplay the messages of course, the example in the documentation shows you exactly how to do that.
The django message Framework offers different ways to do it:
from django.contrib import messages
messages.add_message(request, messages.INFO, 'Your message', extra_tags='more_tags')
# extra_tags is optional
or
messages.success(request,"Your message")
To retrieve it in your template, use something like
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
I have a page with a POST form, that have a action set to some url.
i.e assume this page url is /form_url/ :
..
The view in /submit_url/ take care of the form data. After this, I want to return the same page of the form with a success message.
In the view that take care for the POST form, I use HttpResponseRedirect, in order to "clear" the form data from the browser.
But in this way I can't display a message in the form page, unless I do something like:
return HttpResponseRedirect("/form_url/?success=1")
and then check for this parameter in the template. I don't like this way, since if the user refreshes the page, he will still see the success message.
I've noticed that in django admin site, the delete/add of objects does use redirect after POST submit, and still display a success message somehow.
How?
I've already briefly seen django "messaging" app, but I want to know how it work first..
The django admin uses django.contrib.messages, you use it like this:
In your view:
from django.contrib import messages
def my_view(request):
...
if form.is_valid():
....
messages.success(request, 'Form submission successful')
And in your templates:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li {% if message.tags %} class=" {{ message.tags }} " {% endif %}> {{ message }} </li>
{% endfor %}
</ul>
{% endif %}
For Class Based Views use self.request
I also use self.request.path_info in my return
from django.contrib import messages
class MyCreateView(CreateView):
...
def form_valid(self, form):
....
self.object.save()
messages.success(self.request, 'Form submission successful')
return HttpResponseRedirect(self.request.path_info)
Same template as damio's answer:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li {% if message.tags %} class=" {{ message.tags }} " {% endif %}> {{ message }} </li>
{% endfor %}
</ul>
{% endif %}
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreate(SuccessMessageMixin, CreateView):
model = Author
success_url = '/success/'
success_message = "%(name)s was created successfully"
https://docs.djangoproject.com/en/1.11/ref/contrib/messages/
You don't need to do a redirect to clear the form data. All you need to do is re-instantiate the form:
def your_view(request):
form = YourForm(request.POST or None)
success = False
if request.method == 'POST':
if form.is_valid():
form.save()
form = YourForm()
success = True
return render(request, 'your_template.html', {'form': form})
If the user refreshes the page, they're going to initiate a GET request, and success will be False. Either way, the form will be unbound on a GET, or on a successful POST.
If you leverage the messages framework, you'll still need to add a conditional in the template to display the messages if they exist or not.
Django messages framework stores the messages in the session or cookie (it depends on the storage backend).
If you're using a classed based view with django forms, and granted you've got the messages.html template set up, you can simply pass the 'SuccessMessageMixin' into your view like below
class YourView(SuccessMessageMixin,View):
success_message = 'your message_here'
This will display your message upon form success
I would like to have an alert() message (like in javascript) after method in view.py is complete
My method is
def change_password(request):
dictData = getInitialVariable(request)
in_username = request.POST['txt_username']
in_password = request.POST['txt_password']
in_new_password = request.POST['txt_new_password']
user = authenticate(username=in_username, password=in_password)
if user is not None:
if user.is_active:
u = User.objects.get(username=in_username)
u.set_password(in_new_password)
u.save()
# Redirect to a success page.
return HttpResponseRedirect('/profiles/'+in_username)
After u is saved to database, the popup message will be shown.
How could I implement it?
I think the best solution would be messages (docs)
As described in message levels docs Django suggests to use "INFO" level messages to communicate with users.
By default messages are enabled in Django. If my example doesn't work for you as it is you should check enable messages block
View part:
from django.contrib import messages
def change_password(request):
...your stuff...
messages.info(request, 'Your password has been changed successfully!')
return HttpResponseRedirect('/profiles/'+in_username)
Template part:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
You can paste massage output in specific view or in general templates (layout/header).
There are many ways to do this well (see "flash" in Bootstrap, for example)... but here's how you do literally what you ask about.
In the view you redirect to, pass a message value to your template:
return render_to_response('template_name', message='Save complete')
And in your template, add this script:
<script>
alert('{{ message }}');
</script>
add the messages.success after the send_mail()
from django.contrib import messages
def contact(request):
subject = request.POST['name']
message = request.POST['message']
recipient = settings.EMAIL_HOST_USER
recipient = [recipient,]
email_from = request.POST['mailing']
send_mail( subject, message, email_from, recipient )
messages.success(request, 'Successfully Sent The Message!')
return redirect('send_email')
add this code in your templates in body
{% if messages %}
{% for message in messages %}
{% if message.tags %} <script>alert("{{ message }}")</script> {% endif %}
{% endfor %}
{% endif %}
Simply redirect to /profiles/in_username/password_updated instead
you could use a HTML template on /profiles/in_username/password_updated:
This template redefines the one used in /profiles/in_username and add a javascript with alert
<!DOCTYPE html>
<html lang="en">
<body>
<script>
alert("Your message");
</script>
[...]
</body>
</html>
Simply use render_to_response in that view:
from django.shortcuts import render_to_response
return render_to_response('mytemplate.html', {"in_username": in_username});
See https://docs.djangoproject.com/en/1.7/topics/templates/ for more info on templating.