Integrate Cloudinary with Django Models
In Django August 7, 2022
Updated on May 13, 2023
In this post, we will discuss how we can integrate Cloudinary with Django models and forms. We will build a blog project with a posts app, and each post will have a title field, a content field, and an image field. We will discuss how we can upload that image to the Cloudinary cloud.
Install the Cloudinary module
First, let's install the Cloudinary module. From your terminal type:
pip3 install cloudinary
Start a New Django Project
Let's start a new Django project. In the terminal type:
django-admin startproject my_blog
Then change directories into this folder:
cd my_blog
Create a Posts App
Next, we will create a posts
app:
python manage.py startapp posts
Let's activate this app. Let's open the settings.py
file and add this app to
the INSTALLED_APPS
list as follows:
INSTALLED_APPS = [
'posts.apps.PostsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Set Up Cloudinary
Also, we'll add the Cloudinary module to this list:
INSTALLED_APPS = [
'posts.apps.PostsConfig',
'cloudinary',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Next, we import Cloudinary in settings.py
and provide our Cloudinary
credentials that we can get from the Cloudinary dashboard. You must provide the
cloud_name
, the api_key
, and the api_secret
:
import cloudinary
cloudinary.config(
cloud_name = 'xxxxxxxxx',
api_key = 'xxxxxxxxxxxxxxxx',
api_secret = 'xxx-xxxxxxxxxxxxxxxxxxxxxxx',
)
Add a Post Model
First, we'll import the CloudinaryField
class. Let's open the posts/models.py
file and add
this:
from cloudinary.models import CloudinaryField
Next, we define the Post class:
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
image = CloudinaryField("image")
The Post model has a title
field, a content
field, and also an image
field of
the CloudinaryField
class.
Let's generate the migration file:
python manage.py makemigrations
Next, we run this migration:
python manage.py migrate
Define a PostForm class
Inside the posts/ folder, let's add a forms.py
file. We import the
ModelForm
class, our Post
model, and also the CloudinaryFileField
class:
from django.forms import ModelForm
from .models import Post
from cloudinary.forms import CloudinaryFileField
Here, we define a PostForm
class as follows:
class PostForm(ModelForm):
class Meta:
model = Post
fields = ["title", "content", "image"]
image = CloudinaryFileField(
options={"folder": "blog/", "crop": "limit", "width": 600, "height": 600,}
)
This class has a form field image of the CloudinaryFileField
class. You can specify some options. Here,
I've chosen a folder inside my Cloudinary cloud where I want my images to go, as well as the image
sizes.
Write the views
Let's now write the views. First, import these in the posts/views.py
file:
from django.shortcuts import get_object_or_404, render
from .models import Post
from .forms import PostForm
from django.http import HttpResponseRedirect
from django.urls import reverse
Next. let's add a new
view, which we'll generate the form to add a new post:
def new(request):
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=True)
return HttpResponseRedirect(reverse("posts:detail", args=[post.id]))
else:
form = PostForm()
return render(request, "posts/new.html", {"form": PostForm()})
If the form is valid, we'll redirect the user to the post page with its details.
We need to create this detail
view:
def detail(request, id):
post = get_object_or_404(Post, id=id)
return render(request, "posts/detail.html", {"post": post})
Finally, we will have an index
view:
def index(request):
posts = Post.objects.all()
return render(request, "posts/index.html", {"posts": posts})
Define Our URLs
We do not have URLs for these views, so let's define them. Let's create a urls.py
file
in the posts/
folder and edit it as follows:
from django.urls import path
from . import views
app_name = "posts"
urlpatterns = [
path("", views.index, name="index"),
path("new", views.new, name="new"),
path("<int:id>/", views.detail, name="detail"),
]
Let's add the path to the posts
application in the my_blog/urls.py
file:
First, import the include
function, and then add the path:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('posts/', include('posts.urls'))
]
Write the Templates
The last thing we have to do is to write our templates. Let's create a templates/ folder inside the
posts/
app. Inside the templates/ folder, we add a posts/ sub-folder
where we'll put the three templates.
Let's first create the new.html
template with the form:
<!DOCTYPE html>
<html>
<head>
<title>New Post</title>
</head>
<body>
<h1>New Post</h1>
<form action="{% url 'posts:new' %}" method='post' enctype='multipart/form-data'>
{% csrf_token %}
{{ form.as_p }}
<input type='Submit'>
</form>
</body>
</html>
Next, we'll add the detail.html
template where we'll first initialize Cloudinary tags:
{% load cloudinary %}
Then we can embed the image using the cloudinary
template tag. This is the detail.html
template:
<!DOCTYPE html>
<html>
<head>
<title>{{ post.title }}</title>
</head>
<body>
<h1>{{ post.title }}</h1>
{% cloudinary post.image width=600 height=600 crop='fill' alt=post.title %}
<p>{{ post.content }}</p>
</body>
</html>
We need our index.html template, too, so let's write it:
<!DOCTYPE html>
<html>
<head>
<title>Posts</title>
</head>
<body>
<h1>Posts</h1>
<ul>
{% for post in posts %}
<li><a href = "{% url 'posts:detail' post.id %}">{{ post.title }}</a></li>
{% endfor %}
</ul>
<p><a href="{% url 'posts:new' %}">New Post</a></p>
</body>
</html>
Now, it's time to start the server and add some posts. Run:
python manage.py runserver
Then we can go to http://localhost:8000/posts/new
to add
new posts with images uploaded to the Cloudinary cloud.