MultiValueDictKeyError when passing empty file - python

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

Related

Flask receiving empty POST form

Can't understand, why this code doesn't work, i was trying to understand, but i'm only learning Flask&Py, help me please:
Flask:
#freepylib.route('/register', methods=['POST', 'GET'])
def signup_user():
if request.method == "POST":
username, useremail, userpasswd=request.form['name'], request.form['email'], request.form['password']
reg = Users(uname=username, useremail=useremail, upasswrd=userpasswd)
try:
mydb.session.add(reg)
mydb.session.commit()
token = reg.get_token()
return {'access_token': token}
except Exception as e:
return str(e)
else:
return render_template("register.html")
HTML code:
<form method="POST" name="reg" id="reg">
<input type ="text" class ="fadeIn second" name ="name" placeholder="name">
<input type="text" class="fadeIn second" name="email" placeholder="email">
<input type="text" class="fadeIn third" name="password" placeholder="password">
<input type="submit" name="subm" class="fadeIn fourth" value="Sign Up">
</form>
Error:
(pymysql.err.IntegrityError) (1048, "Column 'uname' cannot be null") [SQL: INSERT INTO `PFL_USERS` (uname, email, upasswrd) VALUES (%(uname)s, %(email)s, %(upasswrd)s)] [parameters: {'uname': None, 'email': None, 'upasswrd': None}] (Background on this error at: http://sqlalche.me/e/13/gkpj)
I think the problem is in your Users class, in the __init__. The kwargs need to match up with how you're calling the constructor from your app code.
For example, changing it to this should help:
def __init__(self, **kwargs):
self.uname = kwargs.get('uname')
self.email = kwargs.get('useremail')
self.upasswrd = kwargs.get('upasswrd')
Special thanks to #ChrisSears, you make my day
Problem was in class, which i forget to add(i'm really sorry)
So, i'll describe:
reg = Users(uname=username, email=useremail, upasswrd=hash_password(userpasswd))
Using this, i've transfer data into Class Users:
def __init__(self, **kwargs):
self.uname = kwargs.get('name')
self.email = kwargs.get('email')
self.upasswrd = kwargs.get('password')
As we can see, name of variables is not correct, so there is the problem, it should be like this:
def __init__(self, **kwargs):
self.uname = kwargs.get('uname')
self.email = kwargs.get('email')
self.upasswrd = kwargs.get('upasswrd')

How to generate 6 digits multiple OTP and insert into database at once with Django

I am generating 6 digits random OTP in my views.py and I just want to insert those many OTPs to be inserted into my Table at once using single QuerySet. Here is my code:
home.html
<form class="" action="" method="post">
{% csrf_token %}
<div class="" style="text-align: center:">
Mobile : <input type="text" name="mobile" value="">
<input type="submit" name="submit" value="Generate OTP">
</div>
</form>
models.py
class otpModel(models.Model):
mobile = models.CharField(max_length=30, blank=False, null=True)
otp = models.CharField(max_length=50, blank=False, null=True)
def __str__(self):
return self.mobile
views.py
import random
from app_name.models import otpModel
def registerOTP(request):
if request.method == 'POST':
mobile = request.POST['mobile']
for i in range(100):
otp = random.randint(100000, 999999)
otp = otpModel.objects.create(mobile=mobile, otp=otp)
if otp:
messages.info(request, 'OTP is saved!!!')
return render(request, 'app_name/otp.html')
else:
return render(request, 'studentexams/otp.html')
Here whenever I enter the Mobile number in the HTML form then only 1 OTP is inserted in the Table. Is there any solutions that I can insert multiple OTPs at a time using single QuerySet
Please give the Code snippet for achieving this task to be done
Try the following
from itertools import islice
def registerOTP(request):
if request.method == 'POST':
mobile = request.POST['mobile']
otps = []
for i in range(100):
otp = random.randint(100000, 999999)
otp_obj = otpModel(mobile=mobile, otp=otp)
otps.append(opt_obj)
# I advise you to do the following in a celery task
# Doing it in the request thread is a bad User experience
batch_size = 50 # 50 is the batch size, you
# can change it to any number you want based on your usecase
while True:
batch = list(islice(otps, batch_size))
if not batch:
break
otpModel.objects.bulk_create(batch, batch_size)
del otps[0:batch_size]
if otp:
messages.info(request, 'OTP is saved!!!')
return render(request, 'app_name/otp.html')
else:
return render(request, 'studentexams/otp.html')
There is a manager method called bulk_create. Using this method you can create list of objects into the database.
bulk_create(objs, batch_size=None, ignore_conflicts=False)
Your code snippet will be like:
otpModel.objects.bulk_create([otpModel(mobile=mobile, otp=otp1),
otpModel(mobile=mobile, otp=otp2),
])
This method inserts the provided list of objects into the database in an efficient manner (generally only 1 query, no matter how many objects there are):
Example:
Entry.objects.bulk_create([
... Entry(headline='This is a test'),
... Entry(headline='This is only a test'),
... ])
You can check out the official documentation here.

Performing two actions with one form in django

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>

Django: edit the choices set of forms.Select widget with dB data linked to current user in templates

Dear Python community,
Could you please share some insights with a newbie like myself regarding the following topic:
I would like to dynamically modify the inputs into form field input, specifically
forms.ChoiceField(choices=((text, name), widget=forms.Select())
As I was not able to access requestfrom class in forms.py, I'd like to try editing the choices from Django template engine. Is it possible to edit the choices, taking the parameters from views.py method using jinja?
The question is conceptual, a few lines of code as an example would be enough, I'll pick it up.
The tricky part is - the data should be dependent on logged-in User's created model instances.
If there's no actual way to do it via python, but js only - please let me know so I don't dry to do the impossible.
Thank you!
Code sample for reference:
forms.py
class InformForm(forms.Form):
flight_number = forms.CharField(5, widget=forms.TextInput())
date = forms.DateField(widget=forms.DateInput(attrs={'class': 'datepicker'}))
template = forms.ChoiceField(choices=tuple([(template.text, template.name) for template in Template.objects.all()]),
widget=forms.Select(attrs={'id': 'select_box',
'onchange': 'javascript:changer();'}))
text = forms.CharField(widget=forms.Textarea(attrs={'id': 'txt_box', 'class': 'latin',
'maxlength': "160", 'onchange': 'javascript:validateTextArea();'}))
template
<form class="form-signin form-container" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-element-wrapper">
<div class="error-form-element">
<span class="error-span">{{field.errors}}</span>
</div>
<div class="form-label">{{field.label_tag}}</div>
<div class="form-data">{{field}}</div>
</div>
{% endfor %}
<button id="cr_inf" type="submit" class="btn btn-lg btn-primary btn-block stl-color"><span id="loader" class=""></span>Create inform</button>
</form>
views.py
class InformFill(View):
form_class = InformForm
temlate_name = 'distrib_db/inform_fill.html'
def get(self, request):
if request.user.is_authenticated():
form = self.form_class(None)
return render(request, self.temlate_name, context={'form': form})
else:
return redirect('distrib_db:login')
def post(self, request):
if request.user.is_authenticated():
form = self.form_class(user=request.user, data=request.POST)
if form.is_valid():
inform = Inform(flt_numbr=form.cleaned_data['flight_number'], date=form.cleaned_data['date'],
template=form.cleaned_data['text'], request=request)
inform.save()
date = form.cleaned_data['date']
flt_numbr = form.cleaned_data['flight_number']
try:
emails, contacts = get_mail_cnt(date, flt_numbr)
# inform = get_object_or_404(Inform, pk=request['pk'])
paxdata = PaxData(inform=inform, emails=' '.join(emails), contacts=' '.join(contacts))
paxdata.save()
return redirect('/inform/{0}/'.format(inform.pk))
# 'distrib_db:detail', context={'pk': inform.id}
except Exception as e:
return render(request, 'distrib_db/sample.html',
context={'date': date, 'flight_number': flt_numbr, 'error': e})
# return render(request, 'distrib_db/sample.html', context={'date': date, 'flt_numbr': flt_numbr})
return render(request, self.temlate_name, context={'form': form})
else:
return redirect('distrib_db:login')
QuerySet issue:
>>> usr = User.objects.filter(username='aleks')
sample = tuple([(template.text, template.name) for template in usr.template_set.all()])
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'QuerySet' object has no attribute 'template_set'
In InformForm class override __init__
def __init__(self, user, *args, **kwargs):
super(InformForm, self).__init__(*args, **kwargs)
self.fields['template'] = forms.ChoiceField(choices="make choice based on user")

'str' does not support the buffer interface while uploading and submitting csv file in Django

I want to upload a csv file and store it in a database. My Django version is 1.9 and Python3.4. Below is the code. My app name is 'pft'
pft/utils.py
from .models import Account
import csv
def handle_uploaded_file(file, valid_fields_method, record_creation_function):
file.seek(0)
# !importtant
# csv file must be encoded in UTF-8
sniffdialect = csv.Sniffer().sniff(file.read(10000), delimiters='\t,;')
file.seek(0)
#print sniffdialect.fieldnames
data = csv.DictReader(file, dialect=sniffdialect)
if not valid_fields_method(data.fieldnames):
return False, -1
result, rows_error = record_creation_function(data)
return result, rows_error
def account_valid_fields(field_names):
required_fields = ('species', 'x', 'y')
for field in required_fields:
if field not in field_names:
return False
return False
def create_account_in_db(dict_data):
list_data = []
result = False
rows_error = 0
for record in dict_data:
species = record['species']
x = record['x']
y = record['y']
account = models.Account(species=species,\
x=x,\
y=y)
list_data.append(account)
if list_data:
# bulk_create will create multiple object in a single query
created_accounts = models.Account.objects.bulk_create(list_data)
if len(list_data) == len(created_accounts):
result=True
else:
rows_error = len(list_data) - len(created_accounts)
return result, rows_error
models.py
class Account(models.Model):
species=models.CharField(max_length=255)
x=models.IntegerField()
y=models.IntegerField()
last_modified = models.DateTimeField(auto_now = True)
first_created = models.DateTimeField(auto_now_add = True)
def __str__(self):
return "%s %s %s" % (self.species, self.x,self.y)
views.py
def add_multiple_accounts(request):
if request.method == 'POST':
csv_upload_form = UploadFileForm(request.POST, request.FILES)
if csv_upload_form.is_valid():
file = csv_upload_form.cleaned_data['file']
csv_result, rows_error = utils.handle_uploaded_file(file, utils.account_valid_fields, utils.create_account_in_db)
if csv_result:
message = 'Successfully imported accounts from the csv file to the database.\n'
message += 'The system is creating Active Directory Accounts using those information in the background.\n'
message += 'Please wait...'
messages.add_message(request, messages.INFO, message)
else:
message = 'There are some errors occured. Please try again.'
messages.add_message(request, messages.INFO, message)
else:
csv_upload_form = UploadFileForm()
return render_to_response('add_multiple.html', locals(), context_instance=RequestContext(request))
urls.py
url(r'^csv',add_multiple_accounts),
add.mutilple.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ csv_upload_form.as_p }}
<button type="submit" class="action green btn-center" name="action" value="add_csv"><span class="label">Upload</span></button>
<input type="submit" />
</form>
When I click the submit button I get the above error. How can I solve this?
try:
file_content = bytes(file.read(10000), 'UTF-8')
sniffdialect = csv.Sniffer().sniff(file_content, delimiters='\t,;')
it is because string in Python3.x is not the same as in python2.x, you need to cast it with bytes and encode as utf-8

Categories

Resources