How to upload a file in Django? [closed] - django

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
What is the minimal example code needed for a "hello world" app using Django 1.3, that enables the user to upload a file?

Phew, Django documentation really does not have good example about this. I spent over 2 hours to dig up all the pieces to understand how this works. With that knowledge I implemented a project that makes possible to upload files and show them as list. To download source for the project, visit https://github.com/axelpale/minimal-django-file-upload-example or clone it:
> git clone https://github.com/axelpale/minimal-django-file-upload-example.git
Update 2013-01-30: The source at GitHub has also implementation for Django 1.4 in addition to 1.3. Even though there is few changes the following tutorial is also useful for 1.4.
Update 2013-05-10: Implementation for Django 1.5 at GitHub. Minor changes in redirection in urls.py and usage of url template tag in list.html. Thanks to hubert3 for the effort.
Update 2013-12-07: Django 1.6 supported at GitHub. One import changed in myapp/urls.py. Thanks goes to Arthedian.
Update 2015-03-17: Django 1.7 supported at GitHub, thanks to aronysidoro.
Update 2015-09-04: Django 1.8 supported at GitHub, thanks to nerogit.
Update 2016-07-03: Django 1.9 supported at GitHub, thanks to daavve and nerogit
Project tree
A basic Django 1.3 project with single app and media/ directory for uploads.
minimal-django-file-upload-example/
src/
myproject/
database/
sqlite.db
media/
myapp/
templates/
myapp/
list.html
forms.py
models.py
urls.py
views.py
__init__.py
manage.py
settings.py
urls.py
1. Settings: myproject/settings.py
To upload and serve files, you need to specify where Django stores uploaded files and from what URL Django serves them. MEDIA_ROOT and MEDIA_URL are in settings.py by default but they are empty. See the first lines in Django Managing Files for details. Remember also set the database and add myapp to INSTALLED_APPS
...
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'database.sqlite3'),
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
...
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
...
INSTALLED_APPS = (
...
'myapp',
)
2. Model: myproject/myapp/models.py
Next you need a model with a FileField. This particular field stores files e.g. to media/documents/2011/12/24/ based on current date and MEDIA_ROOT. See FileField reference.
# -*- coding: utf-8 -*-
from django.db import models
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
3. Form: myproject/myapp/forms.py
To handle upload nicely, you need a form. This form has only one field but that is enough. See Form FileField reference for details.
# -*- coding: utf-8 -*-
from django import forms
class DocumentForm(forms.Form):
docfile = forms.FileField(
label='Select a file',
help_text='max. 42 megabytes'
)
4. View: myproject/myapp/views.py
A view where all the magic happens. Pay attention how request.FILES are handled. For me, it was really hard to spot the fact that request.FILES['docfile'] can be saved to models.FileField just like that. The model's save() handles the storing of the file to the filesystem automatically.
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from myproject.myapp.models import Document
from myproject.myapp.forms import DocumentForm
def list(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('myapp.views.list'))
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render_to_response(
'myapp/list.html',
{'documents': documents, 'form': form},
context_instance=RequestContext(request)
)
5. Project URLs: myproject/urls.py
Django does not serve MEDIA_ROOT by default. That would be dangerous in production environment. But in development stage, we could cut short. Pay attention to the last line. That line enables Django to serve files from MEDIA_URL. This works only in developement stage.
See django.conf.urls.static.static reference for details. See also this discussion about serving media files.
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns('',
(r'^', include('myapp.urls')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
6. App URLs: myproject/myapp/urls.py
To make the view accessible, you must specify urls for it. Nothing special here.
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views',
url(r'^list/$', 'list', name='list'),
)
7. Template: myproject/myapp/templates/myapp/list.html
The last part: template for the list and the upload form below it. The form must have enctype-attribute set to "multipart/form-data" and method set to "post" to make upload to Django possible. See File Uploads documentation for details.
The FileField has many attributes that can be used in templates. E.g. {{ document.docfile.url }} and {{ document.docfile.name }} as in the template. See more about these in Using files in models article and The File object documentation.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Minimal Django File Upload Example</title>
</head>
<body>
<!-- List of uploaded documents -->
{% if documents %}
<ul>
{% for document in documents %}
<li>{{ document.docfile.name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No documents.</p>
{% endif %}
<!-- Upload form. Note enctype attribute! -->
<form action="{% url 'list' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload" /></p>
</form>
</body>
</html>
8. Initialize
Just run syncdb and runserver.
> cd myproject
> python manage.py syncdb
> python manage.py runserver
Results
Finally, everything is ready. On default Django developement environment the list of uploaded documents can be seen at localhost:8000/list/. Today the files are uploaded to /path/to/myproject/media/documents/2011/12/17/ and can be opened from the list.
I hope this answer will help someone as much as it would have helped me.

Demo
See the github repo, works with Django 3
A minimal Django file upload example
1. Create a django project
Run startproject::
$ django-admin.py startproject sample
now a folder(sample) is created.
2. create an app
Create an app::
$ cd sample
$ python manage.py startapp uploader
Now a folder(uploader) with these files are created::
uploader/
__init__.py
admin.py
app.py
models.py
tests.py
views.py
migrations/
__init__.py
3. Update settings.py
On sample/settings.py add 'uploader' to INSTALLED_APPS and add MEDIA_ROOT and MEDIA_URL, ie::
INSTALLED_APPS = [
'uploader',
...<other apps>...
]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
4. Update urls.py
in sample/urls.py add::
...<other imports>...
from django.conf import settings
from django.conf.urls.static import static
from uploader import views as uploader_views
urlpatterns = [
...<other url patterns>...
path('', uploader_views.UploadView.as_view(), name='fileupload'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
5. Update models.py
update uploader/models.py::
from django.db import models
class Upload(models.Model):
upload_file = models.FileField()
upload_date = models.DateTimeField(auto_now_add =True)
6. Update views.py
update uploader/views.py::
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import Upload
class UploadView(CreateView):
model = Upload
fields = ['upload_file', ]
success_url = reverse_lazy('fileupload')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['documents'] = Upload.objects.all()
return context
7. create templates
Create a folder sample/uploader/templates/uploader
Create a file upload_form.html ie sample/uploader/templates/uploader/upload_form.html::
<div style="padding:40px;margin:40px;border:1px solid #ccc">
<h1>Django File Upload</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form><hr>
<ul>
{% for document in documents %}
<li>
{{ document.upload_file.name }}
<small>({{ document.upload_file.size|filesizeformat }}) - {{document.upload_date}}</small>
</li>
{% endfor %}
</ul>
</div>
8. Syncronize database
Syncronize database and runserver::
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver
visit http://localhost:8000/

Generally speaking when you are trying to 'just get a working example' it is best to 'just start writing code'. There is no code here to help you with, so it makes answering the question a lot more work for us.
If you want to grab a file, you need something like this in an html file somewhere:
<form method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" name="submit" value="Upload" />
</form>
That will give you the browse button, an upload button to start the action (submit the form) and note the enctype so Django knows to give you request.FILES
In a view somewhere you can access the file with
def myview(request):
request.FILES['myfile'] # this is my file
There is a huge amount of information in the file upload docs
I recommend you read the page thoroughly and just start writing code - then come back with examples and stack traces when it doesn't work.

I must say I find the documentation at django confusing.
Also for the simplest example why are forms being mentioned?
The example I got to work in the views.py is :-
for key, file in request.FILES.items():
path = file.name
dest = open(path, 'w')
if file.multiple_chunks:
for c in file.chunks():
dest.write(c)
else:
dest.write(file.read())
dest.close()
The html file looks like the code below, though this example only uploads one file and the code to save the files handles many :-
<form action="/upload_file/" method="post" enctype="multipart/form-data">{% csrf_token %}
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
These examples are not my code, they have been optained from two other examples I found.
I am a relative beginner to django so it is very likely I am missing some key point.

I also had the similar requirement. Most of the examples on net are asking to create models and create forms which I did not wanna use. Here is my final code.
if request.method == 'POST':
file1 = request.FILES['file']
contentOfFile = file1.read()
if file1:
return render(request, 'blogapp/Statistics.html', {'file': file1, 'contentOfFile': contentOfFile})
And in HTML to upload I wrote:
{% block content %}
<h1>File content</h1>
<form action="{% url 'blogapp:uploadComplete'%}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input id="uploadbutton" type="file" value="Browse" name="file" accept="text/csv" />
<input type="submit" value="Upload" />
</form>
{% endblock %}
Following is the HTML which displays content of file:
{% block content %}
<h3>File uploaded successfully</h3>
{{file.name}}
</br>content = {{contentOfFile}}
{% endblock %}

Extending on Henry's example:
import tempfile
import shutil
FILE_UPLOAD_DIR = '/home/imran/uploads'
def handle_uploaded_file(source):
fd, filepath = tempfile.mkstemp(prefix=source.name, dir=FILE_UPLOAD_DIR)
with open(filepath, 'wb') as dest:
shutil.copyfileobj(source, dest)
return filepath
You can call this handle_uploaded_file function from your view with the uploaded file object. This will save the file with a unique name (prefixed with filename of the original uploaded file) in filesystem and return the full path of saved file. You can save the path in database, and do something with the file later.

Here it may helps you:
create a file field in your models.py
For uploading the file(in your admin.py):
def save_model(self, request, obj, form, change):
url = "http://img.youtube.com/vi/%s/hqdefault.jpg" %(obj.video)
url = str(url)
if url:
temp_img = NamedTemporaryFile(delete=True)
temp_img.write(urllib2.urlopen(url).read())
temp_img.flush()
filename_img = urlparse(url).path.split('/')[-1]
obj.image.save(filename_img,File(temp_img)
and use that field in your template also.

You can refer to server examples in Fine Uploader, which has django version.
https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader
It's very elegant and most important of all, it provides featured js lib. Template is not included in server-examples, but you can find demo on its website.
Fine Uploader: http://fineuploader.com/demos.html
django-fine-uploader
views.py
UploadView dispatches post and delete request to respective handlers.
class UploadView(View):
#csrf_exempt
def dispatch(self, *args, **kwargs):
return super(UploadView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
"""A POST request. Validate the form and then handle the upload
based ont the POSTed data. Does not handle extra parameters yet.
"""
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_upload(request.FILES['qqfile'], form.cleaned_data)
return make_response(content=json.dumps({ 'success': True }))
else:
return make_response(status=400,
content=json.dumps({
'success': False,
'error': '%s' % repr(form.errors)
}))
def delete(self, request, *args, **kwargs):
"""A DELETE request. If found, deletes a file with the corresponding
UUID from the server's filesystem.
"""
qquuid = kwargs.get('qquuid', '')
if qquuid:
try:
handle_deleted_file(qquuid)
return make_response(content=json.dumps({ 'success': True }))
except Exception, e:
return make_response(status=400,
content=json.dumps({
'success': False,
'error': '%s' % repr(e)
}))
return make_response(status=404,
content=json.dumps({
'success': False,
'error': 'File not present'
}))
forms.py
class UploadFileForm(forms.Form):
""" This form represents a basic request from Fine Uploader.
The required fields will **always** be sent, the other fields are optional
based on your setup.
Edit this if you want to add custom parameters in the body of the POST
request.
"""
qqfile = forms.FileField()
qquuid = forms.CharField()
qqfilename = forms.CharField()
qqpartindex = forms.IntegerField(required=False)
qqchunksize = forms.IntegerField(required=False)
qqpartbyteoffset = forms.IntegerField(required=False)
qqtotalfilesize = forms.IntegerField(required=False)
qqtotalparts = forms.IntegerField(required=False)

Not sure if there any disadvantages to this approach but even more minimal, in views.py:
entry = form.save()
# save uploaded file
if request.FILES['myfile']:
entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True)

I faced the similar problem, and solved by django admin site.
# models
class Document(models.Model):
docfile = models.FileField(upload_to='documents/Temp/%Y/%m/%d')
def doc_name(self):
return self.docfile.name.split('/')[-1] # only the name, not full path
# admin
from myapp.models import Document
class DocumentAdmin(admin.ModelAdmin):
list_display = ('doc_name',)
admin.site.register(Document, DocumentAdmin)

Related

Django redirect from form upload

From the page
This page isn’t working. If the problem continues, contact the site owner.
HTTP ERROR 405
From the terminal
Method Not Allowed (POST): /
Method Not Allowed: /
[20/Dec/2021 22:00:27] "POST / HTTP/1.1" 405 0
How to redirect to the same page after page upload click.
form.html->included in sidebar.html-> included in home.html
<form method = "POST" action='.' enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
views.py
from django.shortcuts import render
from .forms import UserProfileForm
def index(request):
print(request.POST)
return render(request,'home.html')
urls.py
from django.conf import settings
from django.urls import path
from django.views.generic.base import TemplateView # new
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
]
In your urls.py
Change to:
path(' ', index, name = 'home'),
And you also have to import your view in urls.py
Since you are redirecting to the same page, I assume you are also making a get request when you are serving the form on the webpage.
But when the page is served as a response to a GET request, it is not supposed to contain an empty dictionary in the POST attribute.
Thus, it provides an error.
According to me
def index(request):
if request.method == "POST" :
print(request.POST)
return render(request,'home.html')
Should solve the issue
Acc, to the Django documentation
It’s possible that a request can come in via POST with an empty POST dictionary – if, say, a form is requested via the POST HTTP method but does not include form data. Therefore, you shouldn’t use if request.POST to check for use of the POST method; instead, use if request.method == "POST"
For further reference - https://docs.djangoproject.com/en/3.2/ref/request-response/

how to do a live search form ModelChoiceField

how to do a live search in a ModelChoiceField form in the template html ... i write for example a number and a i will get just the data that have that number
i am using django 1.9
models.py
class Suivre(models.Model):
formationffF=models.ForeignKey(FormationDispo,on_delete=models.CASCADE)
numcniF=models.ForeignKey(Personne,on_delete=models.CASCADE)
session = models.CharField(max_length=50)
form.py
class Ajout3 (forms.Form):
numcniF=forms.ModelChoiceField(queryset=Personne.objects.all().order_by('-time'))
formationf =forms.ModelChoiceField(queryset=FormationDispo.objects.all().order_by('time') )
session = forms.CharField(required=True, widget=forms.TextInput())
tamplate.html
<form method="post">
{% load crispy_forms_tags %}
{% csrf_token %}
{{con|crispy}}
<button type="submit" class="btn btn-success" > SAVE</button>
</form>
I would suggest you to use django-admin and ajax_select
Create a file called admin.py in your app.
admin.py
from django.contrib import admin
from myproject.myapp.models import Suivre
from ajax_select import make_ajax_form
# creates model-centric interface where trusted users can manage content on your site.
class SuivreAdmin(admin.ModelAdmin):
model = Suivre
form = make_ajax_form(
Suivre,
{
'numcniF': 'all_personne', # ForeignKeyField
'formationf':'all_formationdispo'
})
# registers admin
admin.site.register(Suivre, SuivreAdmin)
Notice that I am using ajax_select library which will create interface shown in below image.
Install ajax_select:
pip install django-ajax-selects
Add the app:
settings.py
# settings.py
INSTALLED_APPS = (
...
'ajax_select', # <- add the app
...
)
AJAX_LOOKUP_CHANNELS = {
'all_formationdispo': {
'model': 'app.FormationDispo',
'search_field': 'name'
},
'all_personne': {
'model': 'app. Personne',
'search_field': 'name'
},
}
Include the urls in your project:
urls.py
# urls.py
from django.conf.urls import url, include
from django.conf.urls.static import static
from django.contrib import admin
from django.conf import settings
from ajax_select import urls as ajax_select_urls
admin.autodiscover()
urlpatterns = [
# place it at whatever base url you like
url(r'^ajax_select/', include(ajax_select_urls)),

Django - Images won´t be displayed in template, but image url showes up. Urls.py Issue?

Using Django 2.1.5 + Bootstrap 4.2 and some Icons from fontawesome
Hello ,
after a long search I decided to post, because most answer are related to older Django versions.
I am relatively new to Django and I like to test all the Function/Class Views and Modelfields. Now I wanted to test how I can display images linked with my database in my template. But unfortunately, images want not display, all I see is image placeholder icon.
I created an app and 2 simple models, with musicians (with images) and cars. The upload via admin works and the blank url are accessible in the Template via {{ modelone.person_pic }}
PROBLEMS SOLVED - See down Below
aquaman / models.py
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
person_pic = models.ImageField(upload_to='artist/', max_length=255, null=True, blank=True )
def __str__(self):
return "{} - {}".format(self.first_name[:25], self.last_name[:25])
class Data_Sheet(models.Model):
car = models.CharField(max_length=30)
color = models.CharField(max_length=30)
def __str__(self):
return "{} - {}".format(self.car[:25], self.color[:25])
views.py
from django.shortcuts import get_object_or_404, render, redirect
from django.utils import timezone
from django.views.generic.list import ListView
from django.views.generic import TemplateView
from .models import Person, Data_Sheet
<…some other views…>
class ArtistView4(TemplateView):
template_name = 'aquaman/artistview4.html'
def get_context_data(self, **kwargs):
context = super(ArtistView4, self).get_context_data(**kwargs)
context['modelone'] = Person.objects.all()
context['modeltwo'] = Data_Sheet.objects.all()
return context
artistview4.html
{% extends 'base.html' %}
{% load static %}
{% block custom_css %}
<link rel="stylesheet" type="text/css" href="{% static 'css/clear_styles.css' %}">
{% endblock %}
{% block content %}
{% for visual in modelone %}
<div align="center">
<h4 class="">{{ visual.first_name }}</h4>
<h4 class="">{{ visual.last_name }}</h4>
<h4 class="">{{ visual.person_pic }}</h4> <!-- to check if url is displayed -->
</div>
<img src="{{ visual.person_pic.url }}">
</div>
{% endfor %}
{% endblock %}
urls.py
from django.urls import path
from . import views
from .views import AquaListView, AquaListView2, AquaListView3, ArtistView4
app_name='aquaman'
urlpatterns = [
path('home/', views.aqua_home, name='aqua_home'),
path('aqua_listview/', AquaListView.as_view(), name='aqua_listview'),
path('aqua_listview2/', AquaListView2.as_view(), name='aqua_listview2'),
path('aqua_listview3/', AquaListView3.as_view(), name='aqua_listview3'),
path('arstistview4/', ArtistView4.as_view(), name='artistview4'),
]
my approach
As far as I understand the documentation. I have to add this lines to the urls.py in the urlpattern, so that everything gets directed.
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
So my urls.py looks like this now
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from . import views
from .views import AquaListView, AquaListView2, AquaListView3, ArtistView4
app_name='aquaman'
urlpatterns = [
path('home/', views.aqua_home, name='aqua_home'),
path('aqua_listview/', AquaListView.as_view(), name='aqua_listview'),
path('aqua_listview2/', AquaListView2.as_view(), name='aqua_listview2'),
path('aqua_listview3/', AquaListView3.as_view(), name='aqua_listview3'),
path('arstistview4/', ArtistView4.as_view(), name='artistview4'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
This is what i added in my settings.py
TEMPLATES = [
{
<…>
'django.template.context_processors.media',
<…>
},
]
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
'/var/www/static/',
]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
So far nothing changed. Django shows me the last name correctly in the template, but I only see image place holders and no images.
Django Server
Not Found: /media/artist/freddy_mercury.jpg
Not Found: /media/artist/kurt_cobain.jpg
Not Found: /media/artist/ella_fitzgerald.PNG
Not Found: /media/artist/amy_winehouse.PNG
[07/Feb/2019 18:42:49] "GET /media/artist/ella_fitzgerald.PNG HTTP/1.1" 404 2257
When i upload a image via admin from my desktop Django automatically saves the pictures in **MyProject/media/artist>** but at the same time django can not find these images?
If go directly to the images via http://127.0.0.1:8000/media/artist/kurt_cobain.jpg for example, django shows me this:
The current path, media/artist/kurt_cobain.jpg, didn't match any of these.
Even though Django puts the picture via upload in the BaseDir/media/artist folder.
Maybe I missed the "Serving files in development" aka if settings.DEBUG:
https://docs.djangoproject.com/en/2.1/ref/views/
But when I add this also nothing happens.
I really like to thank everyone, who might have a hint
Problem Solved
Alright, I misunderstand something in the Docs maybe it´s not so obvious.
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [...] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
This has to be added in the "MainApp/urls.py" not in your "MyOtherApps/urls.py". I thought just because I only need Images in a specific app I have to add these lines in these specific App urls.py.
Rock On & Peace

Django 2.0 throws AttributeError: ''Image' object has no attribute 'replace'"

When trying to set an html image to my static path + image path in Django 2.0, the django development server displays the following error:
Error during template rendering
In template /Users/arikanevsky/webappgit/ari/templates/ari/software.html, error at line 5
'Image' object has no attribute 'replace'
The Image class from models.py:
class Image(models.Model):
"""This class contains a reference to the ImageField.
It is part of a base of models comprising the webapp.
"""
uplpath = '%Y/%m/%d'
dfltpath = 'page_images/Y/M/D/no_img.jpg'
image = models.ImageField(upload_to=uplpath, default=dfltpath)
def __str__(self):
"""Return human readable string of self.image."""
return self.image.name
The urlpatterns from urls.py:
urlpatterns = [
path('', views.index, name='index'),
path('<int:page_id>/bio/', views.bio, name='bio'),
path('<int:page_id>/software/', views.software, name='software'),
path('<int:page_id>/publications/',
views.publications, name='publications'),
path('<int:page_id>/career/', views.career, name='career'),
path('<int:page_id>/education/', views.education, name='education'),
]
The index method from views.py:
def index(request):
page_list = get_list_or_404(Page.objects.all())
return render(request, 'ari/index.html', {'page_list': page_list})
The index.html file (it is used as named):
{% if page_list %}
<ul>
{% for page in page_list %}
<p>My bio page</p>
<p>My career page</p>
<p>My software page</p>
<p>My publication page</p>.
{% endfor %}
</ul>
{% else %}
<p>No pages are available :(</p>
{% endif %}
The software method from views.py:
def software(request, page_id):
software_page = get_object_or_404(Page, pk=page_id)
return render(request, 'ari/software.html', {'software_page': software_page})
The software.html file:
{% load static %}
<img src = "{% static software_page.image %}" alt = "Profile Picture"/>
The app directory structure is the following:
(I believe we can ignore the .ipynb and pycache dirs)
|-akanev
| |-__pycache__
|-ari
| |-.ipynb_checkpoints
| |-__pycache__
| |-migrations
| | |-__pycache__
| |-templates
| | |-ari
| | | |-page_images
The relevant environment dir paths defined in settings.py:
MEDIA_ROOT: '/Users/arikanevsky/webappgit/ari/templates/ari/page_images'
MEDIA_URL: ''
BASE_DIR: '/Users/arikanevsky/webappgit'
STATICFILES_DIRS: []
STATIC_ROOT: None
STATIC_URL: '/page_images/'
TEMPLATES:
[{'APP_DIRS': True,
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'OPTIONS': {'context_processors': ['django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages']}}]
The img src line in the software.html file throws the error:
Exception Type: AttributeError at /ari/4/software/
Exception Value: 'Image' object has no attribute 'replace'
Would appreciate any and all clues to as what this mysterious error may be!
Thanks :)
You are using the static template tag wrong. It should be used for static files that you want to use on your pages. For example linking to a stylesheet, javascript or images that aren't user uploaded.
See here for more information:
https://docs.djangoproject.com/en/2.0/howto/static-files/
You are trying to get the picture from an uploaded file in your models -
probably done by a user upload (or done in a way that isn't "static"). This is handle via the media url and media root settings. See here:
https://docs.djangoproject.com/en/2.0/topics/files/
The correct way to get the image would be:
<img src = "{{ software_page.image.url }}" alt = "Profile Picture"/>
Best regards,
Andréas

django-ckeditor image upload giving wrong url of the image

When I try text editing and other text related stuffs and save it, the editor does its job nicely. But when I try to upload an image it just take a different url. I am on windows. Is it because of this, cause I saw a post on this post, but it didn't helped me either. It does get saved and they each have their own thumbnails too. But its just that the wrong urls.
I checked the src of the image, and it was like this,
<img alt="" src="/media/3/10/17Hydrangeas.jpg" />
But it should have been like this,
<img alt="" src="/media/2013/10/17/Hydrangeas.jpg" />
And sometimes the src of the image is just like this,
<img alt="" src="/media/3/10/17" />
This is the snippet of my settings.py:
CKEDITOR_UPLOAD_PATH = 'C:/Users/Nanyoo/web/demo/media'
MEDIA_ROOT = 'C:/Users/Nanyoo/web/demo/media'
I've included its url in my urls.py:
(r'^ckeditor/', include('ckeditor.urls')),
models.py:
from django.db import models
from datetime import datetime
from django.contrib.auth.models import User
from time import time
def get_upload_file_name(instance, filename):
return "uploaded_files/%s_%s" %(str(time()).replace('.','_'), filename)
class Blog(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to=get_upload_file_name, blank=True)
pub_date = models.DateTimeField(default=datetime.now)
creator = models.ForeignKey(User, related_name="creator_set")
body = models.TextField()
In the forms.py:
from django import forms
from django_summernote.widgets import SummernoteWidget
from ckeditor.widgets import CKEditorWidget
class BlogForm(forms.Form):
title = forms.CharField(max_length=200,widget=SummernoteWidget())
body = forms.CharField(widget=CKEditorWidget())
In the index.html:
{% for blog in blogs %}
<div id="page">
<h1>{{ blog.title | safe}}</h1>
<p>{{ blog.body | safe}}</p>
</div>
{% endfor %}
my form in the html:
{% block content %}
<form method="post" action=".">
{% csrf_token %}
<fieldset id="create_blog">
{{form.media}}
{{ form.as_p}}
<input type="submit" value="Post Blog" />
</fieldset>
</form>
{% endblock %}
I had a bit of a time getting django-ckeditor up and running with my Django app, but eventually hacked my way through to being able to serve uploaded files on the local machine (during development/testing).
First thing I suggest doing - if you haven't done so already - is read Django's documentation regarding static files. It may help in getting a better idea as to how things are configured and why.
From the django-ckeditor installation documentation, step 4 outlines the purpose of CKEDITOR_UPLOAD_PATH This works similarly to Django's built-in MEDIA_ROOT and STATIC_ROOT, where the path provided isn't necessarily the path in which the file is stored. You must specify a path to store the file upon upload. This may be done by making sure you have a MEDIA_URL global variable declared within your projects settings file.
Once you have the initial setup complete, the final step is to enable Django to serve the files you're working with locally. Please note: This method is to be used for development and debugging purposes only. Do not deploy your code with the following snippet included.
You may read more on this method via Django's static file how-to, within the "Serving static files during development" section.
In your project's urls.py file, add the following bit of code, enabling Django to serve your local data.
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns(
'',
# existing url patterns,
# ...,
) + static(settings.MEDIA_URL, document_root=settings.STATIC_ROOT)
From there, you should be all set.
Just as a quick disclaimer: I am by far a seasoned professional. This method is what has worked for me, given my specific setup and environment. Results may vary.
Hope this helps to get you headed in the right direction. Best of luck!
CKEDITOR_UPLOAD_PATH is relative to MEDIA_ROOT.
https://github.com/django-ckeditor/django-ckeditor#id2
In your case it should be
CKEDITOR_UPLOAD_PATH = ''
This worked for me. To be honest, all these *_PATH issues were probably the hardest parts of Django for me.
UPD: I see that probably your issue was of some other sort. However I noticed the error in your configuration, that's why I wanted to fix that, since I had troubles with that and other people may find this issue and my answer too. Maybe your configuration was even right, if they've changed the defaults since the time of your post.
I made it !!!
Problem solved !!!!!!
I have the same problem just as you.
Did you solve that?
Did you change
CKEDITOR_UPLOAD_PATH = 'uploads/'
to something else?? Don't change if wrong.
Every time after I successfully upload the picture to the server using django-ckeditor, the django-ckeditor would request a URL which looks like this
uploads/2015/06/11/app_software_360.jpg
And that indicates the browser is requesting to
localhost:8000/somewhere/someplace/uploads/2015/06/11/app_software_360.jpg
but not localhost:8000/media/uploads/2015/06/11/app_software_360.jpg This is the actually right URL location, but django-ckeditor just can not find it out. I guess this has something to do with the settings.py
You can check out this page github issue
By adding these to settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = '/media/'
It works!
Thumb up if you think this is helpful. :)