Django Taggit & Image upload with cloudinary

 



Django is like a Rambo to me, a powerful framework with lots of weapons. If you know handle just aim and bang bang 💥 💥 💥....

Overview:

So we are using django-taggit  a simpler approach to tagging with Django, and  image upload using cloudinary, simply to upload image on cloud. For most of people will be helpful who does not have access to aws (s3 bucket) or an alternative to it.

[Note: if you stuck in the process you can get through my GITHUB}

Tools/Technologies:

[Note: Need to have a cloudinary account which is purely free.]

Basic Setup:

$ mkdir django-tagme && cd django-docker 
$ python3 -m venv env
$ source env/bin/activate
(env)$ pip install django cloudinary Pillow django-taggit
(env)$ django-admin startproject tagme
  • our project structure will look like this:

 
└── src
    ├── tagme
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── manage.py
    └── requirements.txt
 
  •  Lets create a new app called books

    python manage.py startapp books

└── src
    ├── books
    |   |__init__.py
    |   ├── admin.py
    |   ├── apps.py
    |   |── models.py 
    |   ├── views.py
    |   
    ├── tagme
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── manage.py
    └── requirements.txt
  • Let make some basic config, create a urls.py on books app.

#books/urls.py
from django.urls import path

app_name = 'books'

urlpatterns = [
 
]

  • And open the main app urls.py, it looks like this:


from django.contrib import admin
from django.urls import pathinclude

urlpatterns = [
    path('admin/'admin.site.urls),
    path(''include('books.urls'namespace='books'))

]
    
  • Next we create a models for book:
from django.contrib.auth.models import User
from django.db import models

from taggit.managers import TaggableManager
from cloudinary.models import CloudinaryField


class Book(models.Model):
    title = models.CharField(max_length=255)
    image = CloudinaryField('image')
    description = models.CharField(max_length=1000)
    author = models.ForeignKey(Useron_delete=models.CASCADE)
    tags = TaggableManager()
    updated = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title


  •  our views.py

#books/views.py 
from django.shortcuts import get_object_or_404renderredirect

from taggit.models import Tag
from books.models import Book

from .forms import BookForm


def home(requestpk=None):
    tag_obj = None

    if not pk:
        books = Book.objects.all()
    else:
        tag_obj = get_object_or_404(Tag, pk=pk)
        books = Book.objects.filter(tags__in=[tag_obj])

    return render(request'home.html', {
        'tag'tag_obj,
        'books'books
    })


def create(request, *args, **kwargs):
    if request.method == 'POST':
        form = BookForm(request.POST, request.FILES)
        if form.is_valid():
            book = form.save(commit=False)
            book.author = request.user
            form.save()
            return redirect('books:home')
    else:
        form = BookForm()
        return render(request'create.html', {
            "form"form
        })


  • Now for urls.py
#books/urls.py
from django.urls import path

from .views import homecreate

app_name = 'books'

urlpatterns = [
  path(''homename='home'),
  path('tag/<str:pk>'homename="books_tag"),
  path('create'createname="create" )
]



  • Now we setup templates and config cloudinary api in settings
 Template Setup:
TEMPLATES = [
    {
        'BACKEND''django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'], #this one
        'APP_DIRS'True,
        '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',
            ],
        },
    },
]
  • Registering our apps and 3rd party app:
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 3rd party app
    'taggit',
    'imagekit',
    'cloudinary',

    # my_app
    'books'
]

  • Cloudinary settings:
import cloudinary
 
cloudinary.config(
  cloud_name = 'Your cloud name',
  api_key = 'your cloud api key',
  api_secret = 'your cloud secret key',
  secure = True
) 

  • Next we create a templates folder in our root directory:

└── src
    ├── books
    |   |__init__.py
    |   ├── admin.py
    |   ├── apps.py
    |   |── models.py 
    |   ├── views.py
    |   
    ├── tagme
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── manage.py
    ├── templates
    └── requirements.txt
 

 Next, we create a templates:

  • base.html
  • create.html
  • home.html
  • base.html
so i will be using some basic template inheritance, and for css i will use bulma.
  • templates/base.html


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Hello Bulma!</title>
    <link rel="stylesheet"  
href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
    <script defer 
 src="https://use.fontawesome.com/releases/v5.14.0/js/all.js"></script>
   <style type="text/css" media="screen">
      body {
        display: flex;
        min-height: 100vh;
        flex-direction: column;
        background-color: info
      }

      #wrapper {
        flex: 1;
      }
    </style>
  </head>
  <body class="has-background-light">
  {% include 'nav.html' %}
  <section class="section">
    <div class="container is-link">
      {% block content %}
            
      {% endblock content %}
    </div>
  </section>
  </body>
</html>
  • templates/home.html

{% extends 'base.html' %}
    {% load cloudinary %} 
 {% block content %}
<h1 class="title">Tag-Me</h1>
<p>Books tagged with <strong>{{ tag.name }}</strong></p>
<div class="columns is-mobile mt-5">
  <div class="column is-half is-offset-one-quarter">
    {% for book in books %}
    <div class="card mt-3">
    
      <div class="card-content">
        <div class="media">
          <div class="media-left">
            <figure class="image is-128x128">
              <img
                src={{book.image.url}}
                alt="Placeholder image"
              />
            </figure>
          </div>
          <div class="media-content">
            {% if book.author%}
            <p class="title is-4">{{ book.author }}</p>
            <p class="subtitle">{{ book.title }}</p>
            {% endif %}
          </div>
        </div>

        <div class="content">
          {{ book.description }} {% if book.tags %}
          <div class="tags">
            {% for tag in book.tags.all %}
            <a href="{% url 'books:books_tag' tag.pk %}">{{ tag }} &nbsp; 
</a>
            {% endfor %}
          </div>
          {% endif %}

          <br />
          <time datetime="2016-1-1"
            ><p>{{ book.updated|date:"M j, Y" }}</p></time
          >
        </div>
      </div>
    </div>

    <p></p>
    {% endfor %}
  </div>
</div>

{% endblock content %}


  • templates/create.html
{% extends 'base.html' %} {% block content %}

<div class="columns is-mobile mt-5">
  <div class="column is-half is-offset-one-quarter ">
    <form
      action="{% url 'books:create' %}"
      method="post"
      enctype="multipart/form-data"
    >
    <p class="title">CREATE BOOK</p>
      <div class="box">
        {% csrf_token %}
      <div class="field">
        <label class="label">Title</label>
        <div class="control">
          <input
            class="input"
            type="text"
            name="title"
            placeholder="Book Title"
          />
        </div>
        {% for err in form.title.errors %}
        <small class="is-danger">{{err}}</small>
        {% endfor %}
      </div>

      <div class="field">
        <label class="label">Description</label>
        <div class="control">
          <input
            class="input"
            name="description"
            type="text"
            placeholder="Book Descriptions"
          />
        </div>
        {% for err in form.description.errors %}
        <small class="is-danger">{{err}}</small>
        {% endfor %}
      </div>

      <div class="field">
        <label class="label">Tags</label>
        <div class="control">
          <input
            class="input"
            type="text"
            name="tags"
            placeholder="Book Tags"
          />
        </div>
        {% for err in form.tags.errors %}
        <small class="is-danger">{{err}}</small>
        {% endfor %}
      </div>
      <div class="field">
        <div class="file is-centered is-boxed is-success has-name">
          <label class="file-label">
            <input class="file-input" type="file" name="image" />
            <span class="file-cta">
              <span class="file-icon">
                <i class="fas fa-upload"></i>
              </span>
              <span class="file-label"> Image Upload </span>
            </span>
            <span class="file-name">
              
            </span>
          </label>
        </div>
      </div>

      <div class="control">
        <button class="button is-primary" type="submit">Submit</button>
      </div>
      </div>
    </form>
  </div>
</div>

{% endblock content %}


  • templates/nav.html
<nav class="navbar is-info" role="navigation" aria-label="main navigation">
  <div class="navbar-brand">
    <a class="navbar-item" href="https://bulma.io">
      <img src="https://bulma.io/images/bulma-logo.png" width="112" 
 height="28">
    </a>

    <a role="button" class="navbar-burger" aria-label="menu" 
 aria-expanded="false" data-target="navbarBasicExample">
      <span aria-hidden="true"></span>
      <span aria-hidden="true"></span>
      <span aria-hidden="true"></span>
    </a>
  </div>

  <div id="navbarBasicExample" class="navbar-menu">
    <div class="navbar-start">
      <a class="navbar-item" href={% url 'books:home' %}>
        Home
      </a>
       <a class="navbar-item" href={% url 'books:create' %}>
        Create
      </a>
      <a class="navbar-item"> 
      </a>
      </div>
    </div>
  </div>
</nav>
 

Still there are lots of improve can be done like update, delete , permission, login, signup so its your turn guys to make it happen. I won't be doing here ...

  • Here, is link for this app demo : Tagme
  • You can access amin panel to but access are limit:
    • username: heroku
    • password: hero@123  
 
Create page

 Home page or list view page:
 
click on tags: it will render page according to tag

Conclusion: django_taggit is simple addons for django which reduce your time in development process. hope you guys made it to here....

Till then bye bye.....😀😀😀




Post a Comment

Previous Post Next Post