I have a Django app with two types of users, lets call them A and B. The two user types have different navigation bars. User type A has a link in their navigation bar to allow them to send a message. The send message form comes up in an overlay, so the form needs to be present in every template, or fetched over AJAX. These users can send a message from any/every page on the site, and each page has its own view. If a message has errors, users should be returned to the same page they were on, and errors should be shown in the form overlay. If it is sent successfully, they should be redirected to a new page that shows their message.
Currently, I have put the form into a separate template that is included on all pages for user type A. I specified the form action as a view called send_message, and I have told that view to render to this template. The view is never called, so I guess this isn't the right way to do it.
How can I render this form in every template? Do I need to call a function from each view, or use a special template tag (I looked at inclusion tags, but I don't think they're right for this situation)? Or should I fetch the form using AJAX? Do I add the form view to every URL?
EDIT: Adding some code to explain.
Say, for example, I am on a page with a simple view like this:
@login_required
def index_view(request, place_id):
categories = Category.objects.all()
return render(request, 'places/categories.html', {'place_id': place_id, 'categories': categories})
The template for this page is extended from a template with the nav bar in it, and that template includes the send a message form, which looks like this:
<div id="message-popup">
<h1>NewMessage</h1>
<form action="{% url "send_message" %}" method="post">
{% csrf_token %}
{% get_message_form as message_form %}
<table>
<tr>
<td>{{ message_form.recipient.label_tag }}{{ message_form.recipient }}</span></td>
<td>{{ message_form.title.label_tag }}{{ message_form.title }}</td>
</tr>
<tr>
<td>{{ message_form.categories.label_tag }}{{ message_form.categories }}</td>
<td>
{{ message_form.content.label_tag }}{{ message_form.content }}
<button type="submit" class="button">Send</button>
<button class="box-close button">Cancel</button>
</td>
</tr>
</table>
</form>
</div>
That form posts to this view:
def send_message_view(request, place_id):
place = Place.objects.get(id=place_id)
if request.POST:
user = get_user_class(request.user)
message_form = forms.SendMessageForm(request.POST, place=place, user=user)
if message_form.is_valid():
message_form.save()
# redirect to page showing the message
else:
message_form = forms.SendMessageForm(place=place, user=user)
return render(request, 'messaging/send_message_form.html', {'message_form': message_form})
The step I'm missing is how to get the form to render in the first place. When I go to the categories page, the form isn't there - obviously because there is no message_form variable in the context. So can I get my send_message_view and my index_view to both run and render the two templates, or is there some other way I have to link it all together?
EDIT:
OK, here is my template tag now:
@register.inclusion_tag('messaging/send_message_form.html', name='get_message_form', takes_context=True)
def get_message_form(context, place, sender, recipient):
message_form = SendMessageForm(context['request'].POST or None, place=place, sender=sender, recipient=recipient)
url = None
if context['request'].method=='POST' and message_form.is_valid():
message = message_form.save()
url = reverse('conversation', kwargs={'place_slug': place.slug, 'message_id': message.id})
""" This doesn't work
return HttpResponseRedirect(url) """
return {'message_form': message_form, 'place_id': place.id, 'message_sent_url': url}
I can't do an HttpResponseRedirect from the template tag, so I need to find some other way of redirecting to the success page. I can send the redirect URL on to the template, but I don't know what I can do with it from there...