Enhancing Django Blog with Custom ModelForms and Article Editing Support
Replacing Default Forms with Styled ModelForms
To improve the appearance and usability of the article creation interface, replace Django’s auto-generated form with a custom ModelForm that integrates Bootstrap styling. Begin by creating a new file blog/forms.py:
from django import forms
from blog.models import Article
class ArticleCreationForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'author', 'summary', 'content']
labels = {
'title': 'Article Title',
'author': 'Author Name',
'summary': 'Brief Summary',
'content': 'Full Content'
}
widgets = {
'title': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Enter a descriptive title'
}),
'author': forms.Select(attrs={'class': 'form-select'}),
'summary': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Summarize the main idea in one sentence'
}),
'content': forms.Textarea(attrs={
'class': 'form-control',
'rows': 12,
'placeholder': 'Write your article using Markdown syntax'
})
}
This form explicitly maps each field to a Bootstrap-styled widget, ensuring consistent visual treatment across inputs. The TextInput and Textarea widgets include semantic placeholder attributes for improved UX, while Select uses form-select for native dropdown styling.
Update templates/article_add.html to render the customizde form:
{% extends 'base.html' %}
{% block title %}New Article{% endblock %}
{% block content %}
<h1>Create a New Post</h1>
<form method="post" class="mt-4">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success mt-3">Publish Article</button>
</form>
{% endblock %}
The as_p randering method wraps each field in <p> tags, preserving spacing and alignment without requiring menual HTML structure.
Implementing Article Update Functionality
Leverage Django’s generic UpdateView to support editing existing articles. In blog/views.py, add:
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from blog.models import Article
from blog.forms import ArticleCreationForm
# ... existing view classes ...
class ArticleUpdateView(UpdateView):
model = Article
form_class = ArticleCreationForm
template_name = 'article_edit.html'
context_object_name = 'article'
Create templates/article_edit.html:
{% extends 'base.html' %}
{% block title %}Edit Article{% endblock %}
{% block content %}
<h1>Edit "{{ article.title }}"</h1>
<form method="post" class="mt-4">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary mt-3">Save Changes</button>
<a href="{% url 'detial_article' article.pk %}" class="btn btn-secondary mt-3 ms-2">Cancel</a>
</form>
{% endblock %}
Register the new route in blog/urls.py:
from django.urls import path
from blog import views
urlpatterns = [
path('', views.HomeView.as_view(), name='home'),
path('article/<int:pk>/', views.ArticleDetailView.as_view(), name='detial_article'),
path('add_article/', views.AddArticleView.as_view(), name='add_article'),
path('article/edit/<int:pk>/', views.ArticleUpdateView.as_view(), name='edit_article'),
]
Finally, expose the edit action in templates/article_detail.html by adding an inline edit link beneath the author information:
<div class="d-flex justify-content-between align-items-center mb-4">
<div>By {{ article.author }} on {{ article.created_at|date:"M d, Y" }}</div>
<a href="{% url 'edit_article' article.pk %}" class="btn btn-outline-primary btn-sm">
<i class="bi bi-pencil-square"></i> Edit
</a>
</div>
This implementation ensures seamless transitions between viewing and editing states while maintaining responsive, accessible form controls powered by Bootstrap.