Performing two actions with one form in django - python

Here I am trying to perform two actions deleting or sending email to selected users.For sending emails a form will be required so I stored checked users in a session like this and after sending email i am removing all the users from session with session['users'].clear().It says sub and msg is required even if I provided .
What's wrong with this code?
Deleting the selected users working fine
def selected_users(request):
form = SendMailForm()
selected_users = get_user_model().objects.filter(id__in=request.POST.getlist('users'))
initial = {'users':[]}
session = request.session.get('users',initial)
if selected_users:
for user in selected_users:
if not user in session['users']:
session['users'].append(user.email)
print('hello1',session['users'])
if selected_users and request.method == 'POST' and 'delete_selected' in request.POST:
count = selected_users.count()
selected_users.delete()
messages.success(request, '{} users deleted.'.format(count))
return redirect('view_users')
elif request.method == 'POST' and 'mail_selected' in request.POST:
form = SendMailForm(request.POST or None)
config = EmailConfiguration.objects.order_by('-date').first()
backend = EmailBackend(host=config.email_host, port=config.email_port, username=config.email_host_user,
password=config.email_host_password, use_tls=config.email_use_tls)
if form.is_valid():
sub = form.cleaned_data['sub']
msg = form.cleaned_data['msg']
for email in session['users']:
email = EmailMessage(subject=sub, body=msg, from_email=config.email_host_user, to=[email],
connection=backend)
email.send()
# clearing users from session after email sends
session['users'].clear()
messages.success(request, 'Your mail sent.')
return redirect('view_users')
else:
print(form.errors)
return render(request, 'send_mail_selected.html', {'users': selected_users,'form':form,'session':session})
forms.py
class SendMailForm(forms.Form):
#to = forms.EmailField(required=False)
sub = forms.CharField(max_length=250)
msg = forms.CharField(widget=forms.Textarea)
template
<form method="POST" >
{% csrf_token %
{{form.as_p}}
<button type="submit" class="btn btn-primary" name="mail_selected">Send </button>
</form>

Related

MultiValueDictKeyError when passing empty file

In my website uploading picture is not compulsory, Therefore when left empty I get
MultiValueDictKeyError
But if i pass an image is dont get an error.
Am I missing some thing?? Thanks in advance....
views.py
if request.method == "POST":
FirstName = request.POST['FirstName']
LastName = request.POST['LastName']
image = request.FILES['image'] #This one
age = request.POST['age']
gender = request.POST['gender']
address = request.POST['address']
PhoneNumber = request.POST['PhoneNumber']
EmailAddress = request.POST['EmailAddress']
Password = request.POST['Password']
RepeatPassword = request.POST['RepeatPassword']
BloodGroup = request.POST['BloodGroup']
try:
if Password == RepeatPassword:
Patient.objects.create(FirstName=FirstName, LastName=LastName, image=image, age=age, gender=gender,
address=address, PhoneNumber=PhoneNumber, EmailAddress=EmailAddress, BloodGroup=BloodGroup)
return redirect('login')
else:
messages.success(
request, ("Passwords do not match. Please try again"))
except Exception as e:
messages.success(
request, ("This email already exists. Try again with another email or recover your account"))
return render(request, 'signup.html')
HTML
<div class="input-div one">
<div class="i">
<ion-icon name="image-sharp"></ion-icon>
</div>
<div class="div">
<h5>Photo</h5>
<input type="file" class="input" name="image">
</div>
</div>
Use .get() instead, i.e:
image = request.FILES.get('image')
It will resolve to None if it can't find it. You can set the default to something else with:
image = request.FILES.get('image', "New default that isn't None")
See: https://www.w3schools.com/python/ref_dictionary_get.asp

Why does my Submit button renders a page that is blank when it is supposed to contain the data that was just updated?

I'm trying to update the values of my database using a HTML Form.
When I Click Edit it brings me to the edit the values above.
However as I am clicking the submit button, it returns me a database but with no other values.
Is there anyone that can help me understand what I did wrong and point me to the right documentation (if any)
editclaims.html:
<div class="arrange2">
<h1>Edit Claim Form - #{{claims.id}} </h1>
</div>
<form method="POST" action="/update/{{claims.id}}">
{% csrf_token %}
views.py:
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
name = request.POST['name']
email = request.POST['email']
claim = request.POST['claim']
claimtype = request.POST.get('claimtype')
description = request.POST['description']
receipt = request.FILES['receipt']
cheque = request.POST.get('Cheque')
form = SaveClaimForm(name=name, email=email, claim=claim, claimtype=claimtype, description=description, receipt=receipt, cheque=cheque)
form.save()
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})
urls.py:
urlpatterns = [
path('existingclaims/', views.viewclaims, name='existingclaims'),
path('editclaims/<int:id>', views.editclaims, name='editclaims'),
path('update/<int:id>', views.updateclaims, name='updateclaims'),
]
It may not resolve all your problems but it will be more readable as answer.
When you get data from HTML then you create new object SaveClaimForm and it will have new ID and you will have the same object in two rows.
You have to get original Claim from database and update values in this object and save it - and then it will save it with original ID and you will have only one `object in database
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
# get original object
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
# update original object
claims.name = request.POST['name']
claims.email = request.POST['email']
claims.claim = request.POST['claim']
claims.claimtype = request.POST.get('claimtype')
claims.description = request.POST['description']
claims.receipt = request.FILES['receipt']
claims.cheque = request.POST.get('Cheque')
# save it with original `ID`
claims.save()
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})
BTW:
Django has special class ModelForm to create forms in HTML. It may also have methods to check if data in HTML are correct - ie. if fields are not empty, if email is correctly constructed (name#domain.com), if phone has only numbers, etc. So using ModelForm can be more useful then writing all manually in code.

Dynamic ChoiceField unable to be validated in form

I have a form that's being given a dictionary of selection, it populates it correctly but on form submit it is not valid. When attempting to print errors, non_field_errors there are just blanks. When I am redirected to the form, now the choice field is populated by one choice and the csrf token from previous submit.
I've tried assigning choices in different ways such as self.fields['calendar'] = forms.ChoiceField(choices=choice_list) directly assign in a different way. self.fields['calendar'].choices = choice_list, a custom validator that ignores the validation, and inline debugging.
Form model:
class CalendarSelectionForm(forms.Form):
calendar = forms.ChoiceField(label="Calendar")
def __init__(self, calendars=None, *args, **kwargs):
super(CalendarSelectionForm, self).__init__(*args, **kwargs)
choice_list = [(calendar_id, calendar_name) for calendar_id, calendar_name in calendars.items()]
if calendars:
self.fields['calendar'].choices = choice_list
View:
if request.method == "POST":
print(request.POST)
cal_sync_form = CalendarSelectionForm(request.POST)
print("Non-field errors " + str(cal_sync_form.non_field_errors()))
print("Reg form errors " + str(cal_sync_form.errors))
# print("Field val " + str(cal_sync_form.calendar))
print("Field data " + str(cal_sync_form.data))
print("Field fields " + str(cal_sync_form.fields) + " Form is " + str(cal_sync_form.is_valid()))
if cal_sync_form.is_valid():
data = cal_sync_form.cleaned_data
print(data)
return render(request, 'management/gcal_sync_dashboard.html')
else:
return render(request, 'management/acct_select.html', {'form': cal_sync_form})
Form template:
<form class="form-import" action="/manage/gcal/sync/" method="post" id = "">
{% csrf_token %}
{{ form.calendar }}
{{ form.errors }}
{{ form.non_field_errors }}
<div class="push clearfix"></div>
<div class="col-sm-6 no-pad push"><input class="btn btn-brand btn-little button filson push-half" type="submit" value="Select email"><i class="fa fa-plus"></i></input>
</div>
</form>
The goal is to validate a posted form, the current print statements print out
<QueryDict: {'csrfmiddlewaretoken': ['sJHE8JJAzmeS0nRjaYZg5KdMlevJiInYY0G4YFJeITH1cVjciIdR1Dq1N28loUIL'], 'calendar': ['email#email.io']}>
Non-field errors
Reg form errors
Field data {}
Field fields OrderedDict([('calendar', <django.forms.fields.ChoiceField object at 0x117323080>)]) Form is False
In your view, you make a call to the CalendarSelectionForm constructor with request.POST as first positional argument. So that means that you call the __init__ function, and request.POST is passed as the calendars parameter.
You can fix this by constructing your form with named parameters. You furthermore will need to pass the same parameter to calendars as you did when you rendered the form with the GET request, since otherwise the choices do not per se match, and the user might have picked an option that is in that case not available during the POST request. Like:
if request.method == 'POST':
cal_sync_form = CalendarSelectionForm(calendars=my_calendars, data=request.POST)
# ...
with my_calendars the same value you pass when you constructed the form in the GET case.

New to DJango need to fill form with initial data in get_data

Here is my html:
{% block my_dashboard_main %}
<form action="status/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
My urls.py:
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'status/$', views.status),
url(r'thanks/$', views.thanks),
)
Here is my views.py:
STATUS_CHOICES = (
("GOOD", "Good"),
("BAD", "Bad"),
("COMPROMISED", "Compromised")
)
def thanks(request):
return render(request, "my_dashboard/ssa_panel/sent.html')
class SsaForm(forms.Form):
status = forms.ChoiceField(choices = STATUS_CHOICES, label="Status:")
def status(request):
print("STATUS CALLED method=",request.method)
if request.method == 'POST': # If the form has been submitted...
form = SsaForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
print("redirect to THANKS!")
return HttpResponseRedirect('thanks/') # Redirect after POST
else:
print("Requesting form\n")
form = SsaForm(initial = {"status", "Good"}) # An unbound form
return render(request, 'my_dashboard/ssa_panel/index.html', {
'form': form,
})
class IndexView(views.APIView):
# A very simple class-based view...
template_name = 'my_dashboard/ssa_panel/index.html'
def get_data(self, request, context, *args, **kwargs):
print("GET_DATA Called", context)
# Add data to the context here...
return context
The first time my page renders the I want the status to show up. It doesn't. Just the Submit button. After I submit once the "Status: [Good] <- combo box" is there. I want to go get the data for the for status in get_data and set it but I don't know how. do I set context['status']="Good" or something like that?
I'm obviously new to DJango and REST stuff.
You are trying to construct your initial value dictionary incorrectly using a comma (,) instead of a colon and also using the wrong choice key. Instead of
form = SsaForm(initial = {"status", "Good"})
try
form = SsaForm(initial = {"status": "GOOD"})

upload file to custom directory in django PYTHON

i have custom form for which i need to upload the image to some directory , below is the code
views function
def user_profile(request):
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid() and form.is_multipart():
new_user = save_file(request.FILES['image'])
return HttpResponse(new_user)
else:
form = ImageForm()
return render_to_response('user_profile.html', { 'form': form })
def save_file(file, path='home/ghrix/ghrixbidding/static/images/'):
''' Little helper to save a file
'''
filename = file._get_name()
fd = open('%s/%s' % (MEDIA_ROOT, str(path) + str(filename)), 'wb')
for chunk in file.chunks():
fd.write(chunk)
fd.close()
and below is the form:
<form method="POST" class="form-horizontal" id="updateform" name="updateform" enctype="multipart/form-data" action="/user_profile/">{% csrf_token %}
<input type="file" id="fileinput" name="fileinput" />
<button class="btn btn-gebo" type="submit">Save changes</button>
</form>
but am getting this error :
The view userprofile.views.user_profile didn't return an HttpResponse object.
The error says that your view is not returning any HttpResponse. There is one case that it's possible -
def user_profile(request):
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid() and form.is_multipart():
new_user = save_file(request.FILES['image'])
return HttpResponse(new_user)
# ------^
# There is not else check. It's possible that the if condition is False.
# In that case your view is returning nothing.
else:
form = ImageForm()
return render_to_response('user_profile.html', { 'form': form })
Regarding that error, the problem is in your view: if your form is invalid, you are not returning a response to the client:
def user_profile(request):
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
new_user = save_file(request.FILES['image'])
return HttpResponse(new_user)
else:
form = ImageForm()
# *** Unindented
return render_to_response('user_profile.html', { 'form': form })
also (I don't have much experience with file uploads) but I don't think you need the is_multipart check - it may be causing your form to appear invalid.

Categories

Resources