I have a contactform in the footer of a website. So it is on every page. It works, with one problem: as soon as it is sent, it doesn't show anymore. More specific I guess when my request is no longer empty.
#register.inclusion_tag('home/tags/contact.html', takes_context=True)
def contact_form(context):
request = context['request']
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['naam']
from_email = form.cleaned_data['email']
message = form.cleaned_data['bericht']
messages.success(request, 'Form submission successful')
try:
send_mail(subject, message, from_email, ['myemailaddress'])
except BadHeaderError:
return HttpResponse('invalid header found')
return context
else:
form = ContactForm()
return {request: 'context.request', 'form': form}
Tips would be appreciated.
It looks like you are returning the template tag's context without the form whenever someone submits a form.
See below:
Do not return the context object until the end of the function, this will make things simpler to work through.
Best to add keys to the context object, this saves you from having to re-add request because it is already there.
Remove the else branch towards the end, you want to send a new (blank) form all the time, even after receiving a response (via POST).
#register.inclusion_tag('home/tags/contact.html', takes_context=True)
def contact_form(context):
request = context['request']
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['naam']
from_email = form.cleaned_data['email']
message = form.cleaned_data['bericht']
messages.success(request, 'Form submission successful')
try:
send_mail(subject, message, from_email, ['myemailaddress'])
except BadHeaderError:
return HttpResponse('invalid header found')
#return context # returning here sends back the context without 'form'
# remove the else branch, you always want to return an empty form
#else:
form = ContactForm()
# return {request: 'context.request', 'form': form}
# return at a consistent place in a consistent way
# add to context, rather then recreating it
context['form'] = form
return context
Another workaround would be just to do a redirect back to the URL that the contact page is on (however, you will loose your messages).
Related
Everything works except when I add a new line via 'enter' in the "Message" field. It goes through if I don't add new lines in the message textfield.
What am i missing here? Tried to solve this problem for 2 days, nothing similar on google.
I feel like there could be the problem of my views.py config:
def success(request):
return render(request, 'home/success.html')
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# send email code goes here
sender_name = form.cleaned_data['name']
sender_email = form.cleaned_data['email']
sender_phone = form.cleaned_data['phone']
sender_message = form.cleaned_data['message']
subject = "Enquiry: {0}".format(sender_message[:50])
message = "New message from {0}\n phone number: {1}\n email: {2}\n\n{3}".format(sender_name, sender_phone, sender_email, sender_message)
recipients = ['john.smith#gmail.com']
sender = "{0}<{1}>".format(sender_name, sender_email)
try:
send_mail(subject, message, sender, recipients, fail_silently=False)
except BadHeaderError:
return HttpResponse('Invalid header found')
return HttpResponseRedirect('success')
else:
form = ContactForm()
return render(request, 'home/contact.html', {'form': form})
Any ideas?
As described in the documentation, a BadHeaderError is raised to "protect against header injection by forbidding newlines in header values".
Since you're copying part of sender_message directly into the subject header, you may be including newlines as well. The simple solution is to strip them out first.
sender_message = form.cleaned_data['message']
clean_message = sender_message.replace('\n', '').replace('\r', '')
subject = "Enquiry: {0}".format(clean_message[:50])
OK im probably doing this all wrong!
I am trying to run a function in a view which calls another view.
This seems to pass my request into the next function as a POST method before loading the form from the second function.
my views.py
''' This section of hte code seems to function correctly '''
#login_required()
def joinLeague(request):
if request.method == 'POST':
league = JoinLeagueQueue(user=request.user)
form = JoinLeagueForm(instance=league, data=request.POST)
if form.is_valid():
form.save()
context = int(league.id) # displays id of model, JoinLeagueQueue
return HttpResponseRedirect(confirmLeague(request, context))
else:
form = JoinLeagueForm()
context = {'form':form}
return render(request, 'userteams/joinleagueform.html', context)
This section of the views file is not working correctly.
it seems to run the POST request without displaying the GET request with the form first.
#login_required()
def confirmLeague(request, league):
# gets ID of application to join league
joinleagueid=JoinLeagueQueue.objects.get(id=league)
pin = joinleagueid.pin # gets pin from application
user = joinleagueid.user # get user from application
leagueinquestion=League.objects.get(leaguePin=pin) # gets the league record for applied league
manager=leagueinquestion.leagueManager # Gets the league manager for league applied for
leaguename=leagueinquestion.leagueName # Gets the league name for league applied for
if request.method == 'POST':
if 'accept' in request.POST:
LeaguesJoinedTo.objects.create(
leaguePin = pin,
playerjoined = user,
)
return redirect('punterDashboard')# user homepage
else:
print("Error in POST request")
else:
context = {'leaguename':leaguename, 'pin':pin, 'manager':manager}
return render(request, 'userteams/confirmleague.html', context)
I now get an error saying Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/userteams/None
Using the URLconf defined in fanfoo_proj.urls, Django tried these URL patterns, in this order:
... im skipping a list of the patterns.
10. userteams/ confirmLeague [name='confirmLeague']
Ok i think the better way would be a HttpRedirect to the second view:
return confirmLeague(request, context)
should change to something like:
return redirect(confirmLeague,args=league)
django doc to urlresolvers: https://docs.djangoproject.com/en/3.0/topics/http/shortcuts/#redirect
def joinLeague(request):
if request.method == 'POST':
league = JoinLeagueQueue(user=request.user)
form = JoinLeagueForm(instance=league, data=request.POST)
if form.is_valid():
form.save()
context = league.id
return HttpResponseRedirect( reverse("your_confirmLeague_url",kwargs={'league':context}) )
else:
form = JoinLeagueForm()
context = {'form':form}
return render(request, 'userteams/joinleagueform.html', context)
def confirmLeague(request, league):
league = get_object_or_404(JoinLeagueQueue, pk=league)
pin = league.pin
if request.method == 'POST':
if 'accept' in request.POST: # This refers to the action from my form which is waiting for a button press in a html form.
LeaguesJoinedTo.objects.create(
leaguePin = pin,
playerjoined = request.user.id,
)
return redirect('punterDashboard')
else:
context = {'league':league}
return render(request, 'userteams/confirmleague.html', context)
I have a list of users with their email adress (only for Staff members), I am trying to send a form to the user.
When I use i.email, I get this error: "to" argument must be a list or tuple
When I use ['i.email'] I don't receive the message.
urls.py
path('users/<int:id>/contact', views.contactUser, name='contact_user'),
views.py
def contactUser(request, id):
i = User.objects.get(id=id)
if request.method == 'POST':
form = ContactUserForm(request.POST)
if form.is_valid():
message = form.cleaned_data['message']
send_mail('Website administration', message, ['website#gmail.com'], ['i.email'])
return redirect('accounts:users')
else:
form = ContactUserForm()
return render(request, 'accounts/contact_user.html', {'form': form, 'username': i})
I am using SendGrid. I have a 'contact us' form which is similar to contactUser and it works fine.
['i.email'] should be [i.email]
I have a web app for ordering parts and I want to include an email when the user orders a part. I am having trouble adding the email function to my function based view.
I have an existing function for saving the order form data and I wanted to simply add the email function to the same view. When I try to add it directly I keep getting error messages about inconsistent white space. So I created a new email function just below the new order view but I don't know how to pass some parameters from one function to the other.
This is close but when I call the New_Order function it throws an error for order_instance not defined.
Views.py
#login_required
def New_Order(request):
if request.user.userprofile.shipment_access:
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
order_instance = form.save(commit=True)
order_instance.save()
return Order_Email()
else:
form = OrderForm()
return render(request, 'app/New_Order.html', {'form': form})
else:
raise PermissionDenied
def Order_Email():
subject = "Part Order" + order_instance.id
orderNum = order_instance.id
from_email = settings.EMAIL_HOST_USER
to_email = ['dummyemail#gmail.com']
message = order_instance
send_mail(subject=subject, from_email=from_email, recipient_list=to_email, message=message, fail_silently=False)
return HttpResponseRedirect('/Orders')
I'm ok with either one combined function or with two functions and passing the parameters from one to the next. If there is a reason I can't add the steps into one function can you explain why? I'm still learning and I'm sure I am missing something in that regard.
Thanks
Max
add an argument to Order_Email :
def Order_Email(order_instance):
and pass the value when you call the function:
return Order_Email(order_instance)
so your code will be like this:
#login_required
def New_Order(request):
if request.user.userprofile.shipment_access:
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
order_instance = form.save(commit=True)
order_instance.save()
return Order_Email(order_instance)
else:
form = OrderForm()
return render(request, 'app/New_Order.html', {'form': form})
else:
raise PermissionDenied
def Order_Email(order_instance):
subject = "Part Order" + order_instance.id
orderNum = order_instance.id
from_email = settings.EMAIL_HOST_USER
to_email = ['dummyemail#gmail.com']
message = order_instance
send_mail(subject=subject, from_email=from_email, recipient_list=to_email, message=message, fail_silently=False)
return HttpResponseRedirect('/Orders')
That is a completely standard function, just pass parameters to it as you normally would. (Note also, the call would need to be inside the if block.)
if form.is_valid():
order_instance = form.save(commit=True)
order_instance.save()
return Order_Email(order_instance)
...
def Order_Email(order_instance):
I have a view function that resubmits data when I refresh the page.
def home(request):
if request.method == 'POST':
form = ListForm(request.POST or None)
if form.is_valid():
form.save()
all_items = List.objects.all
messages.success(request,('Item has been added to List'))
return render(request, 'home.html', {'all_items': all_items})
else:
all_items = List.objects.all
return render(request, 'home.html',{'all_items':all_items})
Any ideas on how to prevent this please. render_to_response is now deprecated from what Ive read.
Thank you
Preventing form resubmission is nothing new, the canonical solution is the post-redirect-get pattern: after a successful post, you return a redirect HTTP response, forcing the user's browser to do a get. The canonical Django "form handler" view (in it's function version) is:
def yourview(request):
if request.method == "POST":
form = YourForm(request.POST)
if form.is_valid():
do_something_with_the_form_data_here()
return redirect("your_view_name")
# if the form isn't valid we want to redisplay it with
# the validation errors, so we just let the execution
# flow continue...
else:
form = YourForm()
# here `form` will be either an unbound form (if it's a GET
# request) or a bound form with validation errors.
return render(request, "yourtemplate.html", {'form': form, ...})