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):
Related
I have a form containing af MultipleChoiceField where the choices are created dynamic based on the given user
class UpdateForm(forms.Form):
def __init__(self,names,*args,**kwargs):
super(UpdateForm,self).__init__(*args,**kwargs)
self.fields["list_names"] = forms.MultipleChoiceField(choices = zip(names,names),widget=forms.CheckboxSelectMultiple,label="Pick some names")
add_new = forms.BooleanField(initial=True, label="Add new names?",required=False)
delete_missing = forms.BooleanField(label = "Delete names?",required=False)
and it works fine as GET-request, the issues arrives with the post-request:
My view is the following:
def update(request):
user = request.user
list_names = MyModel.objects.filter(user=user).all().values_list("nick_name",flat=True).distinct()
form = UpdateWishlistForm(names =list_names)
if request.method == "POST":
post_form = UpdateForm(request.POST)
if post_form.is_valid():
list_names = post_form.cleaned_data["list_names"]
add_new = post_form.cleaned_data["add_new"]
delete_missing = post_form.cleaned_data["delete_missing"]
messages.success(request, "Success")
context = {
"form":form,
}
redirect("home")
else:
#invalid post_form
messages.error(request, "Error")
context = {
"form":form,
}
return render(request, "discounttracker/update.html")
else: #Get request
context = {
"form":form,
}
return render(request, "myapp/update.html",context=context)
The post_form = UpdateForm(request.POST) does not validate and the post_form.errors is empty.
It does contain data though (before calling post_form.is_valid())
print(post_form)
# UpdateForm: <UpdateForm bound=False, valid=Unknown, fields=(add_new;delete_missing;list_names)>
print(request.POST.dict())
#<QueryDict: {'csrfmiddlewaretoken': ['...'], 'add_new': ['on'], 'list_names': ['test_name_1']}>
but I notice it is not bound, thus not validating. But I cannot understand why it's not "binding" when parsing request.POST?
In the POST request, you need to pass the names as well, so:
list_names = MyModel.objects.filter(user=user).values_list("nick_name",flat=True).distinct()
form = UpdateWishlistForm(names=list_names)
if request.method == 'POST':
post_form = UpdateForm(names=list_names, data=request.POST)
# …
# …
But I would advise to work with a ModelMultipleChoiceField [Django-doc] and thus pass a queryset. Since the nick names apparently can contain duplicates, it might be better to make a Nickname model, and use ForeignKeys to that model.
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])
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 created a django form which at the moment I can only save the POST. Would like to add Save and Add another button in my templates and views function. Has anyone found a solutions.
if request.method == "POST":
form = StktxnsForm(request.POST )
if form.is_valid():
new_txns = form.save(commit=False)
new_txns.created_by = request.user
new_txns.save()
return redirect('pending_transactions')
else:
form = StktxnsForm()
return render(request,'new_transaction.html', {'form': form})
You may think use AJAX function to save and continue without reload. Send 'POST' request to save data in Ajax. It will help you.
I used like this in class-based view (vanilla method)
class PackageCreateView(View):
def get(self,request,*args,**kwargs):
return render(request,'package/create_package.html')
def post(self,request,*args,**kwargs):
if request.user.is_authenticated:
if request.method == 'POST':
data = request.POST
name = data.get('name')
detail = data.get('des')
price = data.get('price')
fname = Package.objects.all().filter(name=name)
if fname:
messages.info (request,'sorry name already exits')
return redirect ('create_package')
elif request.POST.get ('continue') :
pac = Package(name=name, detail=detail, price=price)
pac.save()
return redirect('create_package')
else:
pac = Package(name=name, detail=detail, price=price)
pac.save()
return redirect('packagelist')
else:
return redirect ('create_package')
else:
return redirect('login')
Here's one way to do it.
On your template:
<button type="submit" name="save_add" value="True">Save & Add another</button>
In your view:
if form.is_valid():
new_txns = form.save(commit=False)
new_txns.created_by = request.user
new_txns.save()
if request.POST.get('save_add'):
return redirect('create_transaction')
return redirect('pending_transactions')
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).