as from the title, I am trying to implement an external python code to a Django web server.
I am quite new to programming so any hints will be surely helpful.
Long story short: I am trying to set up a form where the user have to insert an aminoacidic sequence. This sequence should pass to my python script, that is able to compare it with all the sequences already present in the database and gives as a result the most similar ones. My problem is that I am not able to let my form and my script talk each others.
I have followed the Django documentation here https://docs.djangoproject.com/en/3.2/topics/forms/ but this did't helped too much.
Also roaming online and browse already asked questions here was unfruitful.
Please find here below the files:
BLAST_page.html (tried both, commented and uncommented)
{% extends "base_generic.html" %}
{% block content %}
<div class="container-fluid" style="text-align: center;" ></div>
<form method="post" action= {% url 'BLAST-process' %}>
{% csrf_token %}
{{ blast }}
<label for="sequence">Type or paste your sequence in the box below</label><br><br>
<input type="text" id="sequence" class="input_text" name="sequence" value="{{ sequence }}" style="width:600px; height:200px;"><br><br>
<input type="submit" value="Submit">
</form>
</div>
{% endblock %}
<!--
<div class="container-fluid" style="text-align: center;" >
<form method="POST" action= {% url 'BLAST-process' %}>
{% csrf_token %}
<label for="sequence">Type or paste your sequence in the box below</label><br><br>
<input type="text" id="sequence" class="input_text" name="sequence" value="{{ sequence }}" style="width:600px; height:200px;"><br><br>
<input type="submit" value="Submit">
</form>
</div>
-->
In order to check if this form works, I have used this simple .php script. The reasoning behind is that if the form works correctly, the inserted data should be echoed. But this doesn't happen.
<html>
<body>
Sequence: <?php echo $_POST["sequence"]; ?><br>
<?php
echo "<h2>Your Input:</h2>";
echo $sequence;
?>
</body>
</html>
forms.py
from django import forms
class blast(forms.Form):
sequence = forms.CharField(help_text="Enter a sequence", label='sequence')
blast.py the script that should receive data from the form
from Bio.Blast.Applications import NcbiblastpCommandline
from io import StringIO
from Bio.Blast import NCBIXML
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
from Bio import SeqIO
import numpy as np
# Create two sequence files
#taken from the textArea.
sequence = sequence
seq1 = SeqRecord(Seq(sequence), id="x")
SeqIO.write(seq1, "seq1.fasta", "fasta")
#SeqIO.write(seq2, "seq2.fasta", "fasta")
# Run BLAST and parse the output as XML
output = NcbiblastpCommandline(query="seq1.fasta",
subject="/Users/santarpia/Documents/tutorial/codorenv/RepOdor/FASTA/db.fasta",
outfmt=5)()[0]
blast_result_record = NCBIXML.read(StringIO(output))
# Print some information on the result
for alignment in blast_result_record.alignments:
for hsp in alignment.hsps:
print('***Alignment****\n')
print('Alignment title', alignment.title)
print('Alignment Length:', alignment.length)
print('E-value:', hsp.expect)
print('Gaps:', hsp.gaps)
print('Identities:', hsp.identities)
print('Positives:', hsp.positives)
print('Score:', hsp.score)
print('Bits:', hsp.bits)
print('Coverage:', hsp.align_length)
print('% Identity:', np.round((hsp.identities / hsp.align_length) * 100, 2))
print("\n")
print (hsp.query[0:])
print("\n")
print (hsp.match[0:])
print("\n")
print (hsp.sbjct[0:])
print('****************************\n\n\n')
As said, any comment on how to set up this would be highly appreciated. If you need more files or information to answer to my question, feel free to ask for them.
So if you followed the documentation correctly after submitting the sequence to the form the code should "enter" the if request.method == 'POST' portion of the view. You can verify this by putting a print("hello world") statement under the if (or an import pdb; pdb.set_trace()). Once there, you can get the sequence from the form with sequence = form.cleaned_data['sequence']. Now to pass it to your script you need your script to be a method that can take in an input (the sequence) so wrap you script in something like def findMostSimilarSequence(sequence): and remove that first line sequence = sequence then in your view you can import the method and call it with the sequence varible from your form.
Related
I am new to Python . I am trying to create a webapp from Django which will read data from Excel file and then it will show that data on webpage in a form of dropdown .
This is the structure of my web app which is I am creating
I have also created a python script which is parsing the excel data and returning the json data
import pandas
import json
# Read excel document
excel_data_df = pandas.read_excel('Test-Data.xlsx', sheet_name='Sheet1')
# Convert excel to string
# (define orientation of document in this case from up to down)
thisisjson = excel_data_df.to_json(orient='records')
# Print out the result
print('Excel Sheet to JSON:\n', thisisjson)
thisisjson_dict = json.loads(thisisjson)
with open('data.json', 'w') as json_file:
json.dump(thisisjson_dict, json_file)
This is output of this script
[{"Name":"Jan","Month":1},{"Name":"Feb","Month":2},{"Name":"March","Month":3},{"Name":"April","Month":4},{"Name":"May","Month":5},{"Name":"June","Month":6},{"Name":"July","Month":7},{"Name":"August","Month":8},{"Name":"Sep","Month":9},{"Name":"October","Month":10},{"Name":"November","Month":11},{"Name":"December","Month":12}]
This is what I am to have on html
<!DOCTYPE html>
<html>
<body>
<h1>The select element</h1>
<p>The select element is used to create a drop-down list.</p>
<form action="">
<label for="months">Choose a Month:</label>
<select name="months" id="month">
<option value="1">Jan</option>
<option value="2">Feb</option>
<option value="3">March</option>
<option value="4">April</option>
</select>
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
Now where I am stuck is how we can integrate this in my webapp and how we can use this Json data to create a dropdown list on my webpage.
You need to do following 3 steps.
Write a view function to see your Excel data in your HTML.
Add your view function in your urls.py file.
Create a loop in your HTML to see your months_data.
1. my_website/views.py
from django.http import Http404
from django.shortcuts import render
def get_months(request):
months_data = your_json
return render(request, 'your_html_path', {'months': months_data})
2. my_website/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.get_months),
]
3. home.html
<!DOCTYPE html>
<html>
<body>
<h1>The select element</h1>
<p>The select element is used to create a drop-down list.</p>
<form action="">
<label for="months">Choose a Month:</label>
<select name="months" id="month">
{% for month in months %}
<option value={{ month.Month }}>{{ month.Name }}</option>
{% endfor %}
</select>
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
Also, you can look for more information about views Writing views | Django documentation
and you can look for more information about urls URL dispatcher | Django documentation
I hope it works for you!
Why dump to json?
Use pyexcel its easy to understand the docs.
link docs
Another option is to use ajax, you can implement the excel output (json Response) in a simple way in your template. If you dont want to use pyexcel (which is in most cases sufficient) let me know, then we can get into an ajax example.
I'm not sure if you're using function or class based view, but pass your data in the context
...
context['months'] = [{"Name":"Jan","Month":1}, ...]
...
Then in the template iterate over it
...
{% for item in months %}
<select name="months" id="month">
<option value="{{ item.Month }}">{{ item.Name }}</option>
</select>
{% endfor %}
...
My UploadForm class:
from app import app
from flask_wtf.file import FileRequired, FileAllowed
from wtforms.fields import MultipleFileField
from wtforms.validators import InputRequired,DataRequired
class UploadForm(FlaskForm):
.
.
.
roomImage = MultipleFileField('Room',validators=[FileAllowed(['jpg', 'png'], 'Image only!'), FileRequired('File was empty!')] )
.
.
.#there are other fields here which are not relevant to the problem at hand
HTML Template
{% extends "base.html" %}
{% block content %}
<h1>Upload Your Images</h1>
<form action="/" enctype="multipart/form-data" method="post" >
{{ form.csrf_token }}
Room<br />
{{form.roomImage()}}
.
.
. <MORE THINGS THAT I HAVE EDITED OUT>
{{form.submit()}}
<br/>
{% if form.errors %}
{{ form.errors }}
{% endif %}
</form>
{% endblock %}
hosts.py to run the check for validation
def upload_image():#NEEDS HEAVY FIXING
"""home page to return the web page to upload documents"""
form = UploadForm()
if form.validate_on_submit():
Using VS's debugging tools, I find that form.validate_on_submit() doesn't work and always fails validation and I get this error on my html page.
{'roomImage': ['File was empty!']}
There is another MultipleFileField control with almost the exact same code.
This issue does not happen when I use FileField to upload one file. The documentation on this is very limited and all I had to go on was this. I don't really know how to solve this issue. I have searched extensively for finding example involving MultipleFileField but they are not using any validation. A thread on Github that I can't find anymore suggested using OptionalValidator, but then that is not an option for me and even that didn't work.
Can someone suggest me a solution?
EDIT:
Even the FileAllowed() validator does not seem to work.
This works for me (found on GitHub "between the lines"):
multi_file = MultipleFileField("Upload File(s)", validators=[DataRequired()])
However
FileAllowed(["xml", "jpg"])
is ignored and does not work for me.
EDIT:
No, sadly, it does not work... It returns True for form.validate() and for form.validate_on_submit() but when you pass no files, by deleting
required=""
from
<input id="multi_file" multiple="" name="multi_file" required="" type="file">
and submit a form, it still evaluate that as True.
So problem sill persist in full, as described...
Regarding FileAllowed validator , it is not working because FileAllowed validator expect one FileStorage object , but MultipleFileField is sending a list of Filestorage objects , which is why it is not working . You have to implement a MultiFileAllowed validator yourself. For More details StackOverflow answer explained with example.
This approach seems to solve the one part of the problem and it uses j-query, which I was unfamiliar with until this point.
So since I am a novice when it comes to web-dev, I was looking for a python based approach to this one. I don't think it exists just yet.
Will update when I fix the multiple file upload issue.
Jsfiddle link
jQuery.validator.setDefaults({
debug: true,
success: "valid"
});
$( "#myform" ).validate({
rules: {
":file": {
required: true,
accept: "image/*"
}
}
});
and
<form id="myform">
<label for="field">Required, image files only: </label>
<input type="file" class="left" id="field" name="field" multiple>
<br/>
<input type="submit" value="Validate!">
</form>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/jquery.validate.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/additional-methods.min.js"></script>
Since I was using wtforms, I tried something called a validation class and inline validators that seems to do the trick.
"""
Validation Class for RoomUpload
"""
class MyRoomValidator(object):
def __init__(self, message=None):
if not message:
message = u"You need to upload the images with the category as well"
self.message = message
def __call__(self, form, field):
print(len(form.roomImage.data))
print((form.roomTypeSelect.data))
if (not form.roomImage.data and form.roomTypeSelect.data == -1) or(form.roomImage.data and form.roomTypeSelect.data == -1) or (not form.roomImage.data and form.roomTypeSelect.data != -1):#check for all possible combinations
raise ValidationError(self.message)
class RoomUpload(FlaskForm):
"""
This is meant for the sub-form for room details upload
containing the details for room and its subtype
roomImage:Upload the room image
roomTypeSelect:The subcategory for room category
The Form will only be submitted if the images are uploaded and
the RoomType will be selected
"""
def validate_roomTypeSelect(form, field):#Inline Validator to ensure if default choice is not chosen
print(field.data)
if field.data == -1:
raise ValidationError('Need to Select Room Type')
def validate_roomImage(form,field):
for roomFile in field.data:
print(roomFile.filename)
if isanImageFile(roomFile.filename) == False:
raise ValidationError("Error!!! Not an Image File ")
roomImage = MultipleFileField(u"Room",validators=[MyRoomValidator(),FileAllowed],id = "roomImage")
roomTypeSelect= SelectField("Room Type",choices=roomTypes,coerce=int,id="roomTypeSelect")
roomSubmit = SubmitField("Upload the images of the room")
I'm fairly new to Django and I'm working on a page that takes in user information. If all of the information is correct, it will proceed to the next page. However, if the user does not provide all given info, it will to refresh the page. My problem is that there are quite a bit of fields the user has to fill out and if the person misses any fields, I don't want them to have to re-type everything out. So my workaround for it is that in the views.py I created a dictionary and it populates it with the input names in the template. However, when I go to run the code, it gives me an error saying that the values in my dictionary do not exist. I'm now thinking that my dictionary is not actually accessing any of the template values.
Here is my template:
<!DOCTYPE html>
{% extends "Checklist/base.html" %}
{% block main_content %}
{% load static %}
<html>
<body>
<form action="{% url 'Checklist:signin_check' %}" method="post">
{% csrf_token %}
<ul style="list-style-type:none">
<li>
<label for="driver_first_name">Driver First Name:</label>
<input type="text" name="driver_first_name" value="" id="driver_first_name">
</li>
<li>
<label for="driver_last_name">Driver Last Name:</label>
<input type="text" name="driver_last_name" value="" id="driver_last_name">
</li>
<li>
<label for="driver_wwid">Driver WWID:</label>
<input type="text" name="driver_WWID" value="" id="driver_WWID" maxlength="8"
onkeypress="return (event.charCode == 8 || event.charCode == 0) ? null : event.charCode >= 48 && event.charCode <= 57">
</li>
<li>
<label for="co_driver_first_name">CO-Driver First Name:</label>
<input type="text" name="co_driver_first_name" value="" id="co_driver_first_name">
</li>
<li>
<label for="co_driver_last_name">CO-Driver Last Name:</label>
<input type="text" name="co_driver_last_name" value="" id="co_driver_last_name">
</li>
<li>
<label for="co_driver_wwid">CO-Driver WWID:</label>
<input type="text" name="co_driver_WWID" value="" id="co_driver_WWID" maxlength="8"
onkeypress="return (event.charCode == 8 || event.charCode == 0) ? null : event.charCode >= 48 && event.charCode <= 57">
</li>
<li>
<input type="submit" value="Continue">
</li>
</ul>
</form>
</body>
</html>
{% endblock %}
Here is the views.py:
def signin_check(request):
driver_info_model = Driver()
if request.method == "POST":
driver_info_form = Driver_Form(request.POST)
c = {'driver_first_name':driver_first_name, 'driver_last_name':driver_last_name,
'driver_WWID':driver_WWID, 'co_driver_first_name':co_driver_first_name,
'co_driver_last_name':co_driver_last_name, 'co_driver_WWID': co_driver_WWID,}
if driver_info_form.is_valid():
driver_info_form.save()
return render(request, 'Checklist/checklist.html')
template = loader.get_template('Checklist/signin.html')
return HttpResponse(template.render(c, request))
any feedback would be greatly appreciated. Thanks!
However, when I go to run the code, it gives me an error saying that
the values in my dictionary do not exist. I'm now thinking that my
dictionary is not actually accessing any of the template values.
From your views.py alone I'm guessing the exception you're running into is that you're assigning dictionary values that aren't defined. For example, in 'driver_first_name':driver_first_name, Python is looking for a variable named driver_first_name but you haven't defined it. The data you're looking for, as Justin alluded to, can be found in requests.POST.
One solution, while more verbose, illustrates what needs to be done:
def signin_check(request):
driver_info_model = Driver()
if request.method == "POST":
driver_info_form = Driver_Form(request.POST)
driver_first_name = request.POST.get('driver_first_name', '')
driver_last_name = request.POST.get('driver_last_name', '')
driver_WWID = request.POST.get('driver_WWID', '')
co_driver_first_name = request.POST.get('co_driver_first_name', '')
co_driver_last_name = request.POST.get('co_driver_last_name', '')
co_driver_WWID = request.POST.get('co_driver_WWID', '')
c = {'driver_first_name': driver_first_name,
'driver_last_name': driver_last_name,
'driver_WWID': driver_WWID,
'co_driver_first_name': co_driver_first_name,
'co_driver_last_name': co_driver_last_name,
'co_driver_WWID': co_driver_WWID, }
if driver_info_form.is_valid():
driver_info_form.save()
return render(request, 'Checklist/checklist.html')
template = loader.get_template('Checklist/signin.html')
return HttpResponse(template.render(c, request))
My problem is that there are quite a bit of fields the user has to
fill out and if the person misses any fields, I don't want them to
have to re-type everything out.
To address your second concern you'll need to deal with your HTML template. Your input fields have a value of "", so any value you pass through your context is not going to reach any of them. Luckily you're on the right path and you're quite close, so all you need to do is fill those values in. For example:
<li>
<label for="driver_first_name">Driver First Name:</label>
<input type="text" name="driver_first_name" value="{{ driver_first_name }}" id="driver_first_name">
</li>
Note that {{ driver_first_name }} is referencing the driver_first_name that's being passed into the context.
Im not 100% sure as i'm fairly new to Django myself, but from what i've done previously you can get the POST data from the request that is passed in, like this:
request.POST['driver_first_name']
which raises an error if no data is present or from
request.POST.get('driver_first_name', 'optionaldefaultvalue')
which returns None if no data is present in the specified field, or an optional default.
It might also be easier to do what you are after with django's inbuilt forms
I am trying to make a flask form which produces the following HTML:
<input type="text" name="title" class="field">
<textarea class="field"></textarea>
<select name="status">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
So far, since I am new to python, I got this far.
{% from "forms/macros.html" import render_field %}
<form method="POST" action="." class="form">
{{ render_field(form.title, class="input text") }}
My question is, have I got this correct so far for the title field, and assuming I have, could someone please explain how I can get a textarea and selectfield? I have read the docs and I am finding it almost impossible to get my head around it.
In my opinion it's better to define the form not in the template but in the controller.
Example form definition :
class CommentForm(Form):
language = SelectField(u'What You Want', choices=CAN_BE_FILLED_LATER_ON)
code = TextAreaField()
All you need later on is to -
Initialize the form by:
comment_form = CommentForm()
Passing it to the template:
return render_template('post_show.jinja2.html', comment_form=comment_form)
Render the form in the template:
<div class="form-group" id='cg-{{comment_form.email.id}}'>
{{comment_form.email.label(class='col-lg-2 control-label',for=comment_form.email.id)}}
<div class="col-lg-9">
{{comment_form.email(class='form-control')}}
<span class="help-block" id='hl-{{comment_form.email.id}}'></span>
</div>
</div
So, I'm making a search function and I would like the previously entered query to remain in the search box when the search results are rendered. Currently the way that I'm doing this is by sending a POST request, grabbing the query and sending that back to the template as a variable. For some reason though, it will only work for the first word of the query, and all subsequent words get dropped. When I render the same variable within a tag however it comes out just as I would expect. Is there something there I'm not doing quite right?
<div id="searchwrapper">
<form action="/search" method="post"> {% csrf_token %}
{% if old_query %}
<input type="text" class="searchbox" name="s" value={{old_query}} />
{% else %}
<input type="text" class="searchbox" name="s" value="" />
{% endif %}
<input type="image" src="static/images/search-icon.svg" class="searchbox_submit" value="" />
</form>
</div>
def search(request):
context = {}
context.update((csrf(request)))
results_string = ""
if request.POST:
results_string = find(request)
old_query = request.POST['s']
context.update({"old_query": old_query})
search_bar = render_to_string("search.html", Context(context))
return HttpResponse(search_bar + results_string)
I don't think that the find method is relevant, but let me know if you think it would be useful and I can post it. The template is the relevant part of "search.html" Like I said, if I add the line <p>{{ old_query }}</p> to the {% if old_query %} section, the right value shows up, but at present if I used a query like hello stackoverflow! I would only get "hello" in as the value for the search field.
This is probably something silly, but I'm fairly new to web dev, so any help is appreciated.
Fix this line to wrap {{old_query}} between quotes:
<input type="text" class="searchbox" name="s" value="{{old_query}}" />
That should give you the whole search instead of the first word.