Django Upload to Other Than Media Location From Admin
Django File (and Epitome) Uploads Tutorial
This tutorial shows how to implement file and and then image uploading with Django. Nosotros'll build a basic Instagram clone.
Setup
Whether you're on a Windows or Mac laptop the Desktop
is a convenient place to put our lawmaking. The location doesn't matter; information technology just needs to exist easily available.
Open the control line and navigate to the Desktop
. Then create a directory, insta
, for our project. Nosotros will create a new virtual surroundings, activate it, and install both Django and pillow which is the Python image process library Django relies on for image files. For non-image file uploads, pillow
is not needed.
# Windows > cd onedrive \ desktop \ code > mkdir insta > cd insta > python - m venv . venv > . venv \ Scripts \ Activate . ps1 (. venv ) > python - m pip install django ~= 4 . 0 . 0 (. venv ) > python - m pip install pillow ~= nine . 0 . 0 # macOS % cd ~/ desktop / code % mkdir insta % cd insta % python3 - m venv . venv % source . venv / bin / activate (. venv ) % python3 - 1000 pip install django ~= iv . 0 . 0 (. venv ) % python - 1000 pip install pillow ~= 9 . 0 . 0
Now create our new Django project called django_project
and a new app called posts
.
(.venv) > django-admin startproject django_project . (.venv) > python manage.py startapp posts
Since we've added a new app we demand to tell Django about it at the bottom of the INSTALLED_APPS
configuration in settings.py
.
# django_project/settings.py INSTALLED_APPS = [ "django.contrib.admin" , "django.contrib.auth" , "django.contrib.contenttypes" , "django.contrib.sessions" , "django.contrib.letters" , "django.contrib.staticfiles" , "posts" , # new ]
Now run python manage.py drift
to setup the new database for our project.
(.venv) > python manage.py migrate
Models
Starting with the database model is a good choice. In our case our model Post
will simply have two fields: championship
and encompass
. We'll as well include a __str__
method below so that the title
appears in our Django admin later on.
# posts/models.py from django.db import models course Post ( models . Model ): title = models . TextField () cover = models . ImageField ( upload_to = 'images/' ) def __str__ ( self ): render self . championship
The location of the uploaded image
will exist in MEDIA_ROOT/images
. In Django, the MEDIA_ROOT
setting is where we define the location of all user uploaded items. We'll fix that now.
If we wanted to use a regular file hither the only difference could be to change
ImageField
toFileField
.
MEDIA_ROOT
Open up config/settings.py
in your text editor. We will add two new configurations. By default MEDIA_URL
and MEDIA_ROOT
are empty and not displayed so we need to configure them:
-
MEDIA_ROOT
is the accented filesystem path to the directory for user-uploaded files -
MEDIA_URL
is the URL we can use in our templates for the files
# config/settings.py MEDIA_URL = "/media/" MEDIA_ROOT = BASE_DIR / "media"
Nosotros could pick a name other than media
hither merely this is the Django convention. We'll also brand an images
folder within it to utilize shortly.
(.venv) $ mkdir media (.venv) $ mkdir media/images
Admin
Now update the posts/admin.py
file and so we can run into our Mail service
app in the Django admin.
# posts/admin.py from django.contrib import admin from .models import Post admin . site . register ( Mail service )
And nosotros're all set! Generate a new migrations file.
(.venv) > python manage.py makemigrations Migrations for 'posts': posts/migrations/0001_initial.py - Create model Post
And so run migrate
to update the database.
(.venv) > python manage.py migrate Operations to perform: Utilise all migrations: admin, auth, contenttypes, posts, session s Running migrations: Applying posts.0001_initial... OK
Now we tin can create a superuser
business relationship to access the admin and so execute runserver
to spin up the local web server for the first time.
(.venv) > python manage.py createsuperuser (.venv) > python manage.py runserver
If you become to http://127.0.0.1:8000/admin you'll be able to log in to the Django admin site. It should redirect y'all to this page:
Click on the "+ Add" link next to Posts
. You tin can add whatever you like but for this tutorial I'g making a postal service on the Django Pony mascot. You tin download it here yourself if you similar.
Upon "Salvage" you will be redirected to the Posts page where nosotros can see all our posts.
If you look within the local media
folder in your project yous'll see under images
in that location is now the djangopony.png
image file. See! I told you that was what MEDIA_URL
would do.
Ok, so at this indicate nosotros're done with the nuts. But let'southward take it a footstep further and display our posts which ways urls.py
, views.py
, and template files.
URLs
The confusing thing most Django is that you oft need 4 dissimilar merely interconnected files for one webpage: models.py
, urls.py
, views.py
, and a template html
file. I find it easiest to reason virtually this by going in order from models -> urls -> views -> template files. Our model is already washed so that means diving into URL routes.
We'll need 2 urls.py
file updates. Outset at the project-level config/urls.py
files we demand to add imports for settings
, include
, and static
. And then ascertain a route for the posts
app. Note we also demand to add the MEDIA_URL
if settings are in DEBUG
mode, otherwise we won't be able to view uploaded images locally.
# config/urls.py from django.contrib import admin from django.conf import settings # new from django.urls import path , include # new from django.conf.urls.static import static # new urlpatterns = [ path ( "admin/" , admin . site . urls ), path ( "" , include ( "posts.urls" )), # new ] if settings . DEBUG : # new urlpatterns += static ( settings . MEDIA_URL , document_root = settings . MEDIA_ROOT )
Next nosotros'll need to sort out the URL routes within the posts
app. Offset create that new file in your text editor posts/urls.py
. Then nosotros'll put all posts on the homepage so again use the empty string ""
every bit our route path.
# posts/urls.py from django.urls import path from .views import HomePageView urlpatterns = [ path ( "" , HomePageView . as_view (), name = "dwelling house" ), ]
This references a view chosen HomePageView
which we'll create adjacent.
Views
We tin apply the generic class-based ListView
hither, import our Post
model, so create a HomePageView
that uses the model and a template called home.html
.
# posts/views.py from django.views.generic import ListView from .models import Post class HomePageView ( ListView ): model = Post template_name = "domicile.html"
Boom! Moving on the last step is that template file called home.html
.
Templates
We take two choices for our template's location. We could put it within the posts
app at posts/templates/posts/home.html
but I observe that structure redundant. Plus it's harder to reason about templates when they are all cached within their corresponding apps. So typically I volition instead create a project-level templates
directory.
(.venv) > mkdir templates
We tell Django to also look here for any templates past updating the TEMPLATES
configuration within config/settings.py
.
# config/settings.py TEMPLATES = [ { ... "DIRS" : [ BASE_DIR / "templates" ], # new ... }, ]
Then create a template file inside this directory, templates/domicile.html
, that volition display the title
and image
for all posts. But similar Instagram would :)
<!-- templates/abode.html --> < h1 >Django Prototype Uploading</ h1 > < ul > {% for post in object_list %} < h2 >{{ post.title }}</ h2 > < img src = "{{ post.comprehend.url}}" alt = "{{ post.title }}" > {% endfor %} </ ul >
Ok, that's information technology! Brand sure the server is running with the python manage.py runserver
command and navigate to our homepage at http://127.0.0.1:8000. Refresh the folio if needed.
And voila! If you add additional posts with a title and epitome via the admin they will appear on the homepage.
Course
Now we can add a form so regular users, who wouldn't have access to the admin, can also add posts. That ways creating a new page with a class.
Let'due south start with the views.py
file. Nosotros'll proper name our new view CreatePostView
which will extend the built-in Django CreateView. We'll also import reverse_lazy to handle the redirect back to our homepage afterward the form has been submitted.
Within the view nosotros specify the model
, a form_class
which we'll create next, the template_name
, and finally a success_url
which is what we want to happen after submission.
# posts/views.py from django.views.generic import ListView , CreateView # new from django.urls import reverse_lazy # new from .forms import PostForm # new from .models import Post class HomePageView ( ListView ): model = Post template_name = "domicile.html" class CreatePostView ( CreateView ): # new model = Postal service form_class = PostForm template_name = "post.html" success_url = reverse_lazy ( "home" )
Next up that course. Commencement create it in your text editor at posts/forms.py
. Then nosotros can extend Django'south congenital-in ModelForm. All nosotros need for our basic form is to specify the correct model Mail
and the fields we want displayed which are title
and cover
.
# posts/forms.py from django import forms from .models import Post class PostForm ( forms . ModelForm ): course Meta : model = Post fields = [ "championship" , "cover" ]
We'll make a defended page for this form at the path of post/
.
# posts/urls.py from django.urls import path from .views import HomePageView , CreatePostView # new urlpatterns = [ path ( "" , HomePageView . as_view (), proper noun = "domicile" ), path ( "post/" , CreatePostView . as_view (), name = "add_post" ) # new ]
Then create the new template at templates/mail service.html
. And fill it with a headline and class. It's important to always add csrf_token
for protection. We're specifying grade.as_p
which means Django volition output each field every bit a paragraph tag.
<!-- templates/post.html --> < h1 >Create Mail Folio</ h1 > < form method = "post" enctype = "multipart/form-data" > {% csrf_token %} {{ form.as_p }} < button type = "submit" >Submit New Post</ push button > </ course >
That's it! Make sure your server is running and get to the page at http://127.0.0.i:8000/post/.
After you submit a new post you'll be redirected back to the homepage and will see all the posts.
Side by side Steps
Hosting this site in product would require a few additional steps. Notably, information technology's likely that you lot would apply WhiteNoise on the server for your static files, notwithstanding WhiteNoise explicitly does not support media files. The common practice is to apply django-storages for this purpose and connect to something like S3.
What else? You lot probably want to put restrictions around the paradigm size which tin can be done initially in the models.py
file or with CSS. Perhaps you want to add together edit and delete options as well for the Mail. And yous'll probable want a thumbnail version of the images too which can be done with sorl-thumbnail.
Source: https://learndjango.com/tutorials/django-file-and-image-uploads-tutorial