Dynamic Web Pages With Django and TinyMCE.
Generated By ChatGPT DALLE

Dynamic Web Pages With Django and TinyMice.

ProspexAI
7 min readMay 19, 2024

--

In this tutorial, I’ll guide you through the process of managing and replacing webpage content dynamically from the database using Django admin panel and django-tinymce. This approach is especially useful when you need to allow non-technical users to update webpage content without delving into the code.

Before we start! 🦸🏻‍

If you like this topic and you want to support me:

  1. Clap my article 50 times; that will really help me out.👏
  2. Follow me on Medium to get my latest article🫶

You can find the project full code under this repo:

https://github.com/tarek421995/Dynamic-Web-Pages.git

Step 1: Creating a Django Project

First, create a new Django project if you don’t already have one.

Create a Virtual Environment

It’s a good practice to use a virtual environment for your projects to manage dependencies. Here’s how to set up a virtual environment on different operating systems:

Linux and macOS

  1. Open your terminal.
  2. Navigate to your project directory.
  3. Create a virtual environment:
python3 -m venv venv
  1. Activate the virtual environment:
source venv/bin/activate

Windows

  1. Open your command prompt.
  2. Navigate to your project directory.
  3. Create a virtual environment:
python -m venv venv
  1. Activate the virtual environment:
.\venv\Scripts\activate

Install Django LTS

Once the virtual environment is activated, install Django LTS (Long Term Support version):

pip install django==5.2

Start the Django Project

  1. Create a new Django project:
django-admin startproject myproject cd myproject
  1. Create a new Django app within your project:
python manage.py startapp myapp
  1. Add myapp and tinymce to your INSTALLED_APPS in settings.py:
INSTALLED_APPS = [
...
'myapp',
'tinymce',
]

Step 2: Setting Up django-tinymce

Install django-tinymce:

pip install django-tinymce

Generate a requirements.txt file to keep track of your dependencies:

pip freeze > requirements.txt

Update the template in settings.py

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": ['templates'], # add this ['templates'].
"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",
],
},
},
]

Configure TinyMCE in settings.py:

TINYMCE_SPELLCHECKER = True
TINYMCE_EXTRA_MEDIA = {
'js': [
'https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js'
],
}
TINYMCE_DEFAULT_CONFIG = {
"height": "320px",
"width": "960px",
"menubar": "file edit view insert format tools table help",
"plugins": "advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code "
"fullscreen insertdatetime media table paste code help wordcount spellchecker",
"toolbar": "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft "
"aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor "
"backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | "
"fullscreen preview save print | insertfile image media pageembed template link anchor codesample | "
"a11ycheck ltr rtl | showcomments addcomment code",
"custom_undo_redo_levels": 10,
'content_css': [
'https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css',
],
'content_js' : [
'https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js'
]
}
import os
MEDIA_URL = '/media/'
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

Step 3: Using django-tinymce in Models

Let’s create a model for webpages that uses TinyMCE for content management.

from django.db import models
from tinymce.models import HTMLField

class Video(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
url = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
return self.title


class WebPage(models.Model):
title = models.CharField(max_length=200)
content = HTMLField(null=True, blank=True)

def __str__(self):
return self.title

# now create the tables in the database 
python manage.py makemigrations
python manage.py migrate

Step 5: Create superuser

python manage.py createsuperuesr ## put your username and password

Step 5: Setting Up Django Admin

Register the WebPage model in the Django admin to manage webpage content easily.

from django.contrib import admin

from .models import Video, WebPage

@admin.register(WebPage)
class WebPageAdmin(admin.ModelAdmin):
list_display = ('title',)

admin.site.register(Video)

Step 5: Add New content to HTMLField

Now login to django admin localhost:8000/admin with your username and password. Navigate to webpage model and create new one title = Web Developer Portfolio

<!-- Video Section -->
<div id="video" class="container my-5">
<h2 class="text-center mb-4">{video_app.Video.title}</h2>
<h2 class="text-center mb-4">{video_app.Video.description}</h2>
<div class="row">
<div class="col-md-8 offset-md-2">
<div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item" src="{video_app.Video.url}" allowfullscreen="allowfullscreen"></iframe></div>
</div>
</div>
</div>

in the content field go to → tools → add source code and place this content:

<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">Portfolio</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="#about">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#skills">Skills</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#projects">Projects</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#video">Video</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#contact">Contact</a>
</li>
</ul>
</div>
</nav>

<!-- Jumbotron -->
<div class="jumbotron text-center bg-primary text-white">
<h1 class="display-4">John Doe</h1>
<p class="lead">A passionate Web Developer</p>
<hr class="my-4">
<p>Creating modern and responsive web applications</p>
<a class="btn btn-secondary btn-lg" href="#contact" role="button">Get in Touch</a>
</div>

<!-- About Section -->
<div id="about" class="container my-5">
<h2 class="text-center mb-4">About Me</h2>
<div class="row">
<div class="col-md-4 text-center">
<img src="https://via.placeholder.com/300" alt="About Me" class="img-fluid rounded-circle mb-3">
</div>
<div class="col-md-8">
<p>Hello! I'm John Doe, a web developer with a passion for creating beautiful and functional websites. With a background in computer science and several years of experience in the industry, I have honed my skills in front-end and back-end development, working with various technologies and frameworks.</p>
</div>
</div>
</div>

<!-- Skills Section -->
<div id="skills" class="container my-5">
<h2 class="text-center mb-4">Skills</h2>
<div class="row">
<div class="col-md-4">
<h3>Front-End</h3>
<ul class="list-unstyled">
<li>HTML/CSS</li>
<li>JavaScript</li>
<li>React</li>
<li>Bootstrap</li>
</ul>
</div>
<div class="col-md-4">
<h3>Back-End</h3>
<ul class="list-unstyled">
<li>Node.js</li>
<li>Express</li>
<li>Django</li>
<li>SQL</li>
</ul>
</div>
<div class="col-md-4">
<h3>Tools & Technologies</h3>
<ul class="list-unstyled">
<li>Git & GitHub</li>
<li>Docker</li>
<li>Kubernetes</li>
<li>AWS</li>
</ul>
</div>
</div>
</div>

<!-- Projects Section -->
<div id="projects" class="container my-5">
<h2 class="text-center mb-4">Projects</h2>
<div class="row">
<div class="col-md-4">
<div class="card">
<img src="https://via.placeholder.com/300" class="card-img-top" alt="Project 1">
<div class="card-body">
<h5 class="card-title">Project 1</h5>
<p class="card-text">Description of Project 1.</p>
<a href="#" class="btn btn-primary">View Project</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<img src="https://via.placeholder.com/300" class="card-img-top" alt="Project 2">
<div class="card-body">
<h5 class="card-title">Project 2</h5>
<p class="card-text">Description of Project 2.</p>
<a href="#" class="btn btn-primary">View Project</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<img src="https://via.placeholder.com/300" class="card-img-top" alt="Project 3">
<div class="card-body">
<h5 class="card-title">Project 3</h5>
<p class="card-text">Description of Project 3.</p>
<a href="#" class="btn btn-primary">View Project</a>
</div>
</div>
</div>
</div>
</div>

<!-- Video Section -->
<div id="video" class="container my-5">
<h2 class="text-center mb-4">{video_app.Video.title}</h2>
<h2 class="text-center mb-4">{video_app.Video.description}</h2>
<div class="row">
<div class="col-md-8 offset-md-2">
<div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item" src="{video_app.Video.url}" allowfullscreen="allowfullscreen"></iframe></div>
</div>
</div>
</div>

<!-- Contact Section -->
<div id="contact" class="container my-5">
<h2 class="text-center mb-4">Contact</h2>
<div class="row">
<div class="col-md-6 offset-md-3">
<form>
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" placeholder="Your Name">
</div>
<div class="form-group">
<label for="email">Email address</label>
<input type="email" class="form-control" id="email" placeholder="Your Email">
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea class="form-control" id="message" rows="3" placeholder="Your Message"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>

<!-- Footer -->
<div class="bg-dark text-white text-center py-3">
<p>&copy; 2024 John Doe. All rights reserved.</p>
</div>

notice how we have replaced the content. {video_app.Video.title} ,{video_app.Video.description} directly from the model we have bluid

Step 3: Displaying Dynamic Content

Now, we’ll set up a view.py file to render the webpage content dynamically by replacing placeholders with data from the database.

# myapp/view.py
import re
from django.apps import apps
from django.utils.html import escape
from django.shortcuts import render
from .models import WebPage

def replace_model_placeholders(text):
pattern = re.compile(r'\{(\w+)\.(\w+)\.(\w+)\}')
def replace_with_model_data(match):
app_label, model_name, field_name = match.groups()
try:
model = apps.get_model(app_label, model_name)
instance = model.objects.first() # Or implement a more specific query
if not instance:
return "[Instance not found]"
value = getattr(instance, field_name, '[Field not found]')
return escape(str(value))
except LookupError:
return '[Model not found]'
except AttributeError:
return '[Field not found]'
except Exception as e:
return f'[Error: {str(e)}]'
return pattern.sub(replace_with_model_data, text)

def webpage_detail(request, pk):
webpage = WebPage.objects.get(pk=pk)
processed_content = replace_model_placeholders(webpage.content)
context = {'webpage': webpage, 'processed_content': processed_content}
return render(request, 'webpage_detail.html', context)

Step 3: Updating the Routes

Update the urls.py file in your app (myapp/urls.py):

from django.urls import path
from .views import webpage_detail

app_name = 'myapp'
urlpatterns = [
path('webpage/<int:pk>/', webpage_detail, name='webpage_detail'),
]

Ensure the app’s urls.py is included in the project’s main urls.py file (e.g., myprojec/urls.py):

from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myapp.urls')), # Include your app's URLs
]

Step 4: Creating the Template

Finally, create a template folder in the root directory and create file called webpage_detail.html to display the webpage content.

<!-- templates/webpage_detail.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ webpage.title }}</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
<h1>{{ webpage.title }}</h1>
<div>{{ processed_content|safe }}</div>
<!-- Scripts -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

</body>
</html>

now go to http://127.0.0.1:8080/1/

you can find the projects in this github repo https://github.com/tarek421995/Dynamic-Web-Pages.git

Conclusion

With these steps, you can now manage and dynamically replace webpage content using the Django admin panel and django-tinymce. This approach empowers non-technical users to update content easily and ensures that your webpages are always up-to-date with the latest data from your database.

Thank you for reading! If you found this guide helpful, please give it a clap and follow me for more insightful content on real-time data analytics and web development with Django. Your support keeps me motivated to share more valuable resources. Let’s stay connected!

Editor’s Note: ProSpexAi is a contributor-driven online publication and community dedicated to providing premier educational resources for data science, machine learning, and deep learning practitioners. We’re committed to supporting and inspiring developers and engineers from all walks of life.

--

--

ProspexAI

Our mission is to educate and inspire individuals, from tech enthusiasts to professionals, about the potential and applications of cutting-edge technologies