I am new to Django.I have the following code on my html file:
{% load staticfiles %}
<form method="post"> {% csrf_token %}
<input type="file" name="file">
<button>Submit</button>
</form>
{{file}}
<img class="hl" src="{{ MEDIA_URL }}photos/abc.png" /></a>
<img class="hl" src="{% static 'blog/images/sec.png' %}" /></a>
and my views.py for the above code is:
if request.method == 'POST':
if 'file' in request.POST:
f = request.POST['file']
a = MyUser(email="frt#wer.com", date_of_birth=date.today())
a.photo.save('somename.png', File(open(f, 'r')))
a.save()
context = {'file': f}
return render(request, 'home.html', context)
Now browsers do not return the absolute path of the file from user's local device, it just gathers filename because ofsome security issues but a.photo.save('somename.png', File(open(f, 'r'))) this part of my code needs absolute path of user local device that is something like /home/abc/Pictures/sec.png all i get is sec.png and hence i am unable to upload.
From python manage.py shell:
>>>a = MyUser(email="frt#wer.com", date_of_birth=date.today())
>>>a.photo.save('somename.png', File(open('/home/abc/Pictures/sec.png', 'r')))
>>>a.save()
This works fine. Is there some workaround. I dont want to use Form.
I would suggest that if you want to allow for a file upload that you use a File form rather than a workaround. A simple and very succinct example can be found here:
Need a minimal Django file upload example
Related
i am using python with flask. i want to send variable to html. getting html output.
ı pass filename variable with render_template. but i dont show in output variable in html
this my python code
#app.route('/', methods=['POST'])
def upload_image():
#cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No image selected for uploading')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
print('upload_image filename: ' + filename)
#cursor.execute("INSERT INTO upload (title) VALUES (%s)", (filename,))
#conn.commit()
#os.remove(os.path.join(app.config['UPLOAD_FOLDER'], filename))
filenamea = 'result_'+str(uuid.uuid4())+'.png'
input_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
output_path = os.path.join(app.config['UPLOAD_FOLDER'], filenamea)
#session = new_session()
input = Image.open(input_path)
output = remove(input)
output.save(output_path)
flash('Image successfully uploaded and displayed below')
return render_template('index.html', filename=filename)
else:
flash('Allowed image types are - png, jpg, jpeg, gif')
return redirect(request.url)
#app.route('/display/<filename>')
def display_image(filename):
#print('display_image filename: ' + filename)
return redirect(url_for('static', filename='uploads/' + filename), code=301)
this my html code:
<body>
{% if filename %}
<div>
<img src="{{url_for('display_image', filename=filename)}}">
</div>
{% endif %}
<div class="wrapper">
<header>Image Backgroud Cleaner</header>
<form action="#">
<input class="file-input" type="file" name="file" multiple hidden>
<i class="fas fa-cloud-upload-alt"></i>
<p>Browse File to Upload</p>
</form>
<section class="progress-area"></section>
<section class="uploaded-area"></section>
</div>
<script src="{{url_for('static', filename='script2.js')}}"></script>
</body>
output
The excerpts above are evidently an incomplete piece of a whole application. Ideally, queries should be reduced to a minimal reproducible example that can be simulated without depending on the rest of your application. This isn't said to be critical but rather to engender your patience and grace if contributors like me have had to make assumptions about your specific scenario to answer your question.
The most pivotal assumption I've made is that the included html text is the template named index.html. Incidentally, it is importing script2.js. Only you know what that script is doing (not to belabor the point) so please pardon if you've already addressed the following suggestions in that javascript file or elsewhere.
Neither of the routes posted above have a GET method that will return index.html. <form action="#"> suggests that you are using the upload_image route for both the GET and POST of index.html, so the absence of a corresponding route supporting the GET method is very likely one of the problems that you're facing.
There are at least two approaches you could try to add a corresponding route supporting the GET method that returns index.html:
Method A - Update upload_image route to support GET method
#app.route('/', methods=['GET','POST'])
def upload_image():
if request.method == 'POST':
# All the POST logic goes here
else:
# All the GET logic goes here
return render_template('index.html')
Method B - Create a corresponding new route
#app.route('/upload_page', methods=['GET'])
def upload_page():
return render_template('index.html')
A reason for preferring method B is that you can leverage the upload_image route elsewhere to upload files in your application in different templating contexts if you haven't constrained it to index.html. I've favored method B in my index.html example below. Note that I've changed <form action="#" to <form action="/" so that it routes explicitly to the base route on POST.
Not only do you need to add a route that supports the GET method and returns index.html, but you also need to add method="post" enctype="multipart/form-data" as attributes of the form in index.html. Otherwise it will always default as a GET request and the intended POST will fail.
The hidden attribute is preventing the file input from rendering. If you're not intentionally using it for an unstated purpose, remove it.
You also need a submit input or other interface of some sort in index.html to submit the upload form.
Depending on if and how you configured an upload folder path, you may be running into issues with the route #app.route('/display/<filename>'). You actually don't need this route at all if you leverage the default by adding a folder named static in your application root directory. You need only change the url_for argument from display_image to static for this to work.
Given the above adjustments, index.html now looks like this:
<body>
{% if filename %}
<div>
<img src="{{url_for('static', filename=filename)}}">
</div>
{% endif %}
<div class="wrapper">
<header>Image Backgroud Cleaner</header>
<form action="/" method="post" enctype=multipart/form-data>
<input class="file-input" type="file" name="file" multiple>
<input type="submit">
<i class="fas fa-cloud-upload-alt"></i>
<p>Browse File to Upload</p>
</form>
<section class="progress-area"></section>
<section class="uploaded-area"></section>
</div>
<script src="{{url_for('static', filename='script2.js')}}"></script>
</body>
With these adjustments, you now should be getting the output variable filename that your question stated you were not getting in index.html and the <img> preview of filename should be visible in the rendered page.
home.html
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name = 'img' >
<button type="submit"> Post On Facebook </button>
</form>
views.py
def home(request):
if request.method == 'POST':
# get the image absolute location
return render(request,'home.html')
I want the file path, so that I can upload the file on facebook using GraphAPI.
You need to set your upload path in your models file.
Then you can save it to that particular path in your view function.
For details refer - https://simpleisbetterthancomplex.com/tutorial/2016/08/01/how-to-upload-files-with-django.html
Rather than using Django admin, I wanted to make my own images upload on my site at 127.0.0.1/upload
Now, when I upload an image through the admin, it works fine. But when I upload though my own image, it's not uploading (and not to the correct path).
template
<form action="{% url 'app:publish' %}" method="post">
{% csrf_token %}
<input type="file" name="image_upload" accept="image/*" />
<input type="submit" />
</form>
views.py
def publish(request):
image = request.POST.get('image_upload', '')
photo = Photo(image=image)
photo.save()
return HttpResponseRedirect('/')
models.py
def generate_path(self, filename):
url = "%s/%s" % (self.college.name, filename)
return url
class Photo(models.Model):
image = models.ImageField(upload_to=generate_path, default="buildingimages/default.png")
This is was I usually do for text based fields, but I'm assuming files work differently, and that's why this is not working?
The object shows up in my admin after I try my upload, but the image itself doesn't seem to upload nor go to the right directory.
So the generate_path works totally fine when I upload through the admin, but through my own publish view, it seems to upload to /media/ and then it says image does not exist?
Any idea what I'm doing wrong
Uploaded files are stored in request.FILES, not in request.POST.
I am currently creating an upload function and I am having a hard time in saving the forms. Currently I have two separate forms, one for the profile detail and one for the upload picture only.
This is my views.py right now:
user = UserViewModel(username, profile)
# This method is to save the file to the directory
user.save_to_directory(userName, request.FILES['upload_picture'])
form = UserForm(request.POST)
if form.is_valid():
user.firstname = form.cleaned_data['firstname']
user.lastname = form.cleaned_data['lastname']
return render(request, 'profile.html',{'message':message})
else:
return render(request, 'profile.html',{'errorMessage':user.errorMessage})
This is my template:
<form name="upload_picture" id="upload_picture" accept-charset="utf-8" enctype="multipart/form-data" action="{% url 'actuser:profile' userName %}" method="post">
<input type="file" name="upload_picture"/>
</form>
<button type="button" onclick="document.getElementById('upload_picture').submit();">
Upload
</button>
<form name="update_profile" id="update_profile" action="{% url 'user:profile' userName %}" method="post">
firstname<input type="text" name="firstname">
lastname<input type="text" name="lastname">
</form>
Using this code I could save the uploaded file to the directory but the other form can't be save. There isn't really an error message when I upload the file but its asking for the other fields to be filled even though it is populated in the separate form.
What I want is to save the uploaded picture to the directory without affecting the other form, vice versa.
Thanks in advance to those who can suggest a solution.
(Flask novice alert)
Given the following to upload and save a file in Flask:
#app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return render_template_string('''
{% extends "base.html" %}
{% block content %}
<h4>File uploaded</h4>
<p><a href={{ url_for('members_page') }}>Back</a></p>
{% endblock %}
''')
elif not allowed_file(file.filename):
return render_template_string('''
{% extends "base.html" %}
{% block content %}
<h3>Please try again</h3>
<h4>File must be a .csv</h4>
<p><a href={{ url_for('upload_file') }}>Back</a></p>
{% endblock %}
''')
return render_template_string('''
{% extends "base.html" %}
{% block content %}
<h4>Upload CSV of Company/URL data</h2>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" />
</form>
{% endblock %}
''')
I wish to make filename available within another function:
#app.route('/scrape', methods=['GET', 'POST'])
#login_required # Use of #login_required decorator
def scrape():
parser = ConfigParser()
parser.read('config.ini')
keywords = parser.get('scrape', 'keywords').replace(' ', '').split(',')
jobs = scraper.scrape(os.path.join(app.config['UPLOAD_FOLDER'], filename), keywords)
The above is the desired intent, where filename is known by the scrape fucnction. Obviously that is not yet the case. With upload_file() already having a return value in the positive case (a confirmation page), how can I make filename available? UPLOAD_FOLDER will contain more than just the uploaded file, so I can't just join this path with whatever is in there.
Where this a non-Flask program, I would probably return locals() and then access the appropriate key, but I imagine that's not possible here if I want to maintain the serving up of the confirmation page.
You need to somehow connect two requests. If many users request the first one, a then someone requests a /scrape, how do you know which one is requesting, and which filename does he belong to?
You can use a session (a cookie session for example, see http://pythonhosted.org/Flask-Session/) to keep track of the uploaded file. Store the filename in the session, and the when the same user (with the same cookie) requests /scrape, you can retrieve the filename from the user session.
You can include the filename to use in the second request. This way, the user himself has to keep track of the files that he uploaded.
In either case, but especially in the latter, it's important to think about ownership of files: which user has access to which file on your system?
Pickle the filename in upload_file(), unpickle it in scrape().
PICKLED_CSV_FILENAME = 'pickled_csv_file_name'
def pickle_filename(filename, pickle_file):
with open(os.path.join(UPLOAD_FOLDER, pickle_file),'wb') as p:
pickle.dump(filename, p)
def load_pickled_filename(pickle_file):
return pickle.load(open(os.path.join(UPLOAD_FOLDER, pickle_file), 'rb'))
in upload_file():
pickle_filename(filename, PICKLED_CSV_FILENAME)
then in scrape():
jobs = scraper.scrape(os.path.join(app.config['UPLOAD_FOLDER'], load_pickled_filename(PICKLED_CSV_FILENAME)), keywords)
pickle_filename(filename, PICKLED_CSV_FILENAME)
Obviously not a sustainable solution in the case of many users/files, but it is a single user, single file scenario so it's acceptable.