Django: send emails to users - django

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]

Related

How to convert json to form in Django?

I'm developing a Django project, and the team want to seperate the front-end and the back-ed, so I'm using Django to develop api. The format of the data transmitting is json. However, I want to use the defalt user package (django.contrib.auth), and I have to use Form. How could I convert the json received from the frontend to the form that I'm going to use in backend? thanks!
I have tried the silly code as below and it does not work.
#require_http_methods(["POST"])
def register(request):
form = CustomUserCreationForm(data=request.POST)
response = {"status": "success"}
if form.is_valid():
new_user = form.save()
print("valid")
return JsonResponse(response)
This is how your view must look if you want to register new user with custom form :
def register(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
response = {}
if form.is_valid():
# The form is valid, now we can save the user in the db
new_user = form.save()
response = {"status": "success", "message": "User created"}
return JsonResponse(response)
else:
# Invalid form
response = {"status": "error", "message": "Form is invalid"}
else:
# It's not a post request ( GET or others)
# Instantiate an empty form
form = CustomUserCreationForm()
context = {
'form': form,
}
return render(request, 'register_template.html', context=context)

redirect to created object after form submission

Goal: To redirect to the 'build log' after the form is submitted
view:
#login_required
def buildLogCreate(request, pk):
post = Post.objects.get(pk=pk)
if request.user.id != post.author_id:
raise PermissionDenied()
currentUser = request.user
form = BuildLogForm()
if request.method == 'POST':
form = BuildLogForm(request.POST, request.FILES)
if form.is_valid():
formID = form.save(commit=False)
formID.author = request.user
formID.post_id = pk
formID.save()
return redirect('build-log-view', formID.pk)
context = { 'form':form, }
return render(request, 'blog/buildlog_form.html', context)
The url structure setup is post->buildlog(subpost) ie: /post/118/build-log/69/
The form gets successfully submitted but I get the error NoReverseMatch at /post/118/build-log-form/ Reverse for 'build-log-view' with arguments '(69,)' What confuses me is the url is still on the post form and not build log view but the argument 69 is the correct build log id so it should be working.
url to be redirected to
path('post/<int:pk>/build-log/<int:pkz>/', views.BuildLogDisplay, name='build-log-view'),
The URL pattern has two parameters: the primary key of the post object, and the primary key of the build log.
You can thus pass this with:
return redirect('build-log-view', pk, formID.pk)
or with named parameters:
return redirect('build-log-view', pk=pk, pkz=formID.pk)

sending email from Django view

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):

Contactform in footer of page

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).

Django send mail back to the user who sends in form

I have a contactform on my site.
When submitted a mail is sent to me. But I also want to send the user a mail, letting the user know that I have received the form submission.
When I try to put the email value as a recipient, I get this error: AssertionError: "to" argument must be a list or tuple
Anyone see what is wrong with my code?
def show_contactform(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
f = ContactForm(request.POST)
f.save()
email = form.cleaned_data['email']
subject = "New contact from website"
recipients = ['contact#company.com']
rendered = render_to_string('forms/email_body.html', {'form':form)
to_user_subject = "Contact registred"
to_user_rendered = render_to_string('form/to_user_email_contact.html', {'form_headline':subject})
#Send content to celery worker for asynchronous mail outbox - sending to company
tasks.send_email.delay(subject=subject, rendered=rendered, email=email, recipients=recipients)
#Send content to celery worker for asynchronous mail outbox - sending to the user who sent the form
tasks.send_email.delay(subject=to_user_subject, rendered=to_user_rendered, email=recipients, recipients=email)
return HttpResponseRedirect('/form/contact/success/')
else:
form = ContactForm() # An unbound form
return render(request, 'contact/form.html', {
'form': form,
})
#task()
def send_email(subject, rendered, email, recipients):
msg = EmailMultiAlternatives(subject, rendered, email, recipients)
msg.attach_alternative(rendered, "text/html")
msg.send()