How to Upload and Serve Images in Django Content Feed
Add the Blog and Photo Models
Our final goal is to build a feed that will contain blog posts and photos from creators that a user has subscribed to.
However, before we can do that, we need to:
-
Add the models to hold these photo and blog posts.
-
Provide users with the means to create the posts.
First, let's look at the models. All our changes are now concerning theblog
app, so let's add this toblog/models.py
.
# blog/models.py from django.conf import settings from django.db import models class Photo(models.Model): image = models.ImageField() caption = models.CharField(max_length=128, blank=True) uploader = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) date_created = models.DateTimeField(auto_now_add=True) class Blog(models.Model): photo = models.ForeignKey(Photo, null=True, on_delete=models.SET_NULL, blank=True) title = models.CharField(max_length=128) content = models.CharField(max_length=5000) author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) date_created = models.DateTimeField(auto_now_add=True) starred = models.BooleanField(default=False)
As you can see, blog posts can be optionally linked to aphoto
by theForeignKey
relationship. ThePhoto
model contains an image stored in theImageField
.
Let's make and run the migrations.
(ENV) ~/fotoblog (master) → python manage.py makemigrations Migrations for 'blog': blog/migrations/0001_initial.py - Create model Photo - Create model Blog (ENV) ~/fotoblog (master) → python manage.py migrate Operations to perform: Apply all migrations: admin, auth, authentication, blog, contenttypes, sessions Running migrations: Applying blog.0001_initial... OK
OK, now that the models are configured, let's look at handling user-uploaded images in Django.
Upload Images Using a Form
Before uploading images to Django, you need to configure where to store the media content. In this instance, media content refers to files and images that are user-uploaded.
Step 1: Configuresettings.py
To do this, you must configure two values insettings.py
.
First, theMEDIA_URL
, which is the URL from which Django will attempt to serve media. In some cases, this could be a full URL to another host if you are using a third-party service to serve your media.
For this class, you're going to serve the images locally, so you can provide a path that points to your localhost server.
The second setting to configure is theMEDIA_ROOT
. It points to the directory on your machine where Django should save uploaded images.
The configuration to add is:
# fotoblog/settings.py MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR.join_path('media/')
Step 2: Add the Media to the URL Patterns
Now you need to update your URL patterns so that the uploaded media is accessible via a URL.
To do this, add:
# fotoblog/urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns = [ ... ] if settings.DEBUG: urlpatterns += static( settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Now the images in yourMEDIA_ROOT
directory will be served at the path given byMEDIA_URL
.
Step 3: Create a Form That Can Handle Image Uploads
Now that the settings are configured, let's add a form for uploading photos.
It's really simple to do this: you can use aModelForm
, and Django will handle the file transfer and save it to the file system for you.
Let's create aforms.py
file inblog/
and add the following:
# blog/forms.py from django import forms from . import models class PhotoForm(forms.ModelForm): class Meta: model = models.Photo fields = ['image', 'caption']
Step 4: Build the View to Handle Image Uploads
Now let's add the view. Usually, you only populate a form with therequest.POST
object, but as you are transferring an image, you also have to provide it with any files sent with the request. Do this by giving the argumentrequest.FILES
.
We want to set theuploader
field on thePhoto
to the user currently logged in. You can create thePhoto
object without saving it to the database by saving the form with the argumentcommit=False
. Then setuploader
to the correct value, and finally save the model to store it in the database.
# blog/views.py from django.shortcuts import redirect, render from . import forms @login_required def photo_upload(request): form = forms.PhotoForm() if request.method == 'POST': form = forms.PhotoForm(request.POST, request.FILES) if form.is_valid(): photo = form.save(commit=False) # set the uploader to the user before saving the model photo.uploader = request.user # now we can save photo.save() return redirect('home') return render(request, 'blog/photo_upload.html', context={'form': form})
Uploading the image is easy as theModelForm
does all the heavy lifting!
Step 5: Add the Template
Let's add the template.
# blog/templates/blog/photo_upload.html {% extends 'base.html' %} {% block content %} <h2>Upload a Photo</h2> <form method="post" enctype="multipart/form-data"> {{ form.as_p }} {% csrf_token %} <button type="submit" >Submit</button> </form> {% endblock content %}
Note how you add the attributeenctype="multipart/form-data"
to the<form>
tag. This is required for the form to handle file uploads.
Step 6: Update the URL Patterns
Now add the view to the URL patterns.
# fotoblog/urls.py import blog.views urlpatterns = [ ... path('photo/upload/', blog.views.photo_upload, name='photo_upload') ]
Step 7: Create a Feed
To see the uploaded photos, you need to fetch them in the view. Refactor thehome
view to do this.
# blog/views.py from . import models @login_required def home(request): photos = models.Photo.objects.all() return render(request, 'blog/home.html', context={'photos': photos})
Then update the template. You can get the path of the photo from theurl
property on theimage
field. Theurl
property gets constructed from theMEDIA_URL
setting configured earlier.
# blog/templates/blog/home.html {% extends 'base.html' %} {% block content %} <h2>Photos</h2> {% for photo in photos %} <img src="{{ photo.image.url }}"> <p>{{ photo.caption }}</p> {% endfor %} {% endblock content %}
Great! Now let's test the new functionality.
First, upload a new photo.
Then check the feed.
Success! Users can now upload their photos and you can see them in the feed.
Next, you are going to add functionality that allows a user to update their profile photo.
Exercise: Upload a Profile Photo
You want to allow users to upload and display profile photos.
To do this, you are going to build a profile photo upload facility.
We have built out an updated version of the site, complete with some styling. Let's see what it looks like.
Pretty slick!
The styling is in CSS. If you want, you can take some time to style your site to your own design now. Or pull down from the GitHub repo to include the changes in your site.
You will see that your user profile is now displayed at the left of the page, with the link "Change Profile Photo" below it.
Currently, this link doesn't do anything. To make it work, you will need to:
-
Create an
UploadProfilePhotoForm
form inauthentication/forms.py
- this can be aModelForm
forUser
. -
Create a view
upload_profile_photo
in theauthentication
app and configure the view to update the user's profile photo. -
Create a template for this view and add the view to the URL patterns.
-
Link to the page from the
Change Profile Photo
link. -
Display the user's profile photo in the user profile if they have uploaded a profile photo; otherwise, display the default profile photo. You can check this with
{% if user.profile_photo %}
.
If you get stuck:
-
Make sure you pass
instance=request.user
to yourUploadProfilePhotoForm
to update the user logged in. -
Include
enctype="multipart/form-data">
in your<form>
tag. -
Don't forget to pass
request.FILES
toUploadProfilePhotoForm
when handling thePOST
data.
Once you are finished, check your solution against the solution in GitHub.
Let's Recap!
-
You can define the
MEDIA_x
constants in the settings to dictate where Django will store user-uploaded files. -
The
ImageField
allows you to upload images to the server using aModelForm
.
Now that you can allow users to upload their own media in a view, you are ready to handle multiple forms on a single page.
Source: https://openclassrooms.com/en/courses/7107341-intermediate-django/7264297-create-an-image-upload-facility
0 Response to "How to Upload and Serve Images in Django Content Feed"
Post a Comment