Skip to content

Chapter 13: Complete Blog System ​

13.3 Advanced Features ​

User System Integration ​

Integrate complete user system functionality:

python
# views.py (accounts app)
from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib import messages
from django.views.generic import CreateView, DetailView, UpdateView
from django.urls import reverse_lazy
from django.contrib.auth.models import User
from .forms import UserRegistrationForm, UserProfileForm
from .models import UserProfile

class RegisterView(CreateView):
    form_class = UserRegistrationForm
    template_name = 'accounts/register.html'
    success_url = reverse_lazy('blog:home')
    
    def form_valid(self, form):
        response = super().form_valid(form)
        # Auto-login user
        login(self.request, self.object)
        messages.success(self.request, 'Registration successful! Welcome to join us.')
        return response

class ProfileView(DetailView):
    model = User
    template_name = 'accounts/profile.html'
    context_object_name = 'profile_user'
    
    def get_object(self, queryset=None):
        # If user is logged in, show own profile; otherwise show specified user's profile
        if self.request.user.is_authenticated:
            return self.request.user
        return super().get_object(queryset)

class ProfileUpdateView(UpdateView):
    model = User
    form_class = UserProfileForm
    template_name = 'accounts/profile_edit.html'
    success_url = reverse_lazy('accounts:profile')
    
    def get_object(self, queryset=None):
        return self.request.user
    
    def form_valid(self, form):
        response = super().form_valid(form)
        messages.success(self.request, 'Profile updated successfully!')
        return response

# forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import UserProfile

class UserRegistrationForm(UserCreationForm):
    email = forms.EmailField(required=True)
    
    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")
    
    def save(self, commit=True):
        user = super().save(commit=False)
        user.email = self.cleaned_data["email"]
        if commit:
            user.save()
            # Create user profile
            UserProfile.objects.create(user=user)
        return user

class UserProfileForm(forms.ModelForm):
    # User basic information
    first_name = forms.CharField(max_length=30, required=False)
    last_name = forms.CharField(max_length=30, required=False)
    email = forms.EmailField(required=False)
    
    class Meta:
        model = UserProfile
        fields = ['bio', 'location', 'birth_date', 'website', 'avatar']
        widgets = {
            'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
            'location': forms.TextInput(attrs={'class': 'form-control'}),
            'birth_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
            'website': forms.URLInput(attrs={'class': 'form-control'}),
            'avatar': forms.FileInput(attrs={'class': 'form-control'}),
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Initialize user basic information fields
        if self.instance and self.instance.user:
            self.fields['first_name'].initial = self.instance.user.first_name
            self.fields['last_name'].initial = self.instance.user.last_name
            self.fields['email'].initial = self.instance.user.email
    
    def save(self, commit=True):
        profile = super().save(commit=False)
        # Save user basic information
        user = profile.user
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.email = self.cleaned_data['email']
        if commit:
            user.save()
            profile.save()
        return profile

Rich Text Editor ​

Integrate rich text editor:

# Install django-ckeditor
# pip install django-ckeditor

# settings.py
INSTALLED_APPS = [
    # ...
    'ckeditor',
    'ckeditor_uploader',
]

# CKEditor configuration
CKEDITOR_CONFIGS = {
    'default': {
        'toolbar': 'full',
        'height': 300,
        'width': '100%',
    },
}

CKEDITOR_UPLOAD_PATH = "uploads/"
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# models.py
from ckeditor.fields import RichTextField
from ckeditor_uploader.fields import RichTextUploadingField

class Article(models.Model):
    # ... other fields ...
    content = RichTextUploadingField()  # Use rich text editor
    excerpt = RichTextField(blank=True, config_name='default')

# forms.py
from ckeditor.widgets import CKEditorWidget

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ['title', 'category', 'tags', 'content', 'excerpt', 'featured_image', 'status']
        widgets = {
            'content': CKEditorWidget(config_name='default'),
            'excerpt': CKEditorWidget(config_name='default'),
            # ... other widgets ...
        }

Cache Optimization ​

Implement cache optimization:

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
    }
}

# views.py
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
from django.core.cache import cache

@method_decorator(cache_page(60 * 15), name='dispatch')  # Cache for 15 minutes
class ArticleListView(ListView):
    # ... view code ...

class ArticleDetailView(DetailView):
    # ... other code ...
    
    def get_object(self, queryset=None):
        # Use cache to get article
        slug = self.kwargs['slug']
        cache_key = f'article_{slug}'
        article = cache.get(cache_key)
        
        if article is None:
            article = super().get_object(queryset)
            # Cache article for 1 hour
            cache.set(cache_key, article, 60 * 60)
        else:
            # If retrieved from cache, still need to increase view count
            article.view_count += 1
            article.save(update_fields=['view_count'])
        
        return article

# Use template fragment caching
# templates/blog/article_list.html
{% load cache %}

{% cache 900 article_list page_obj.number %}
    {% for article in articles %}
        <!-- Article list content -->
    {% endfor %}
{% endcache %}

# Cache sidebar in template
{% cache 1800 sidebar %}
    <!-- Sidebar content -->
{% endcache %}

SEO Optimization ​

Implement SEO optimization features:

# models.py
class Article(models.Model):
    # ... other fields ...
    meta_description = models.TextField(blank=True, help_text="SEO description")
    meta_keywords = models.CharField(max_length=255, blank=True, help_text="SEO keywords")
    
    def get_meta_description(self):
        """Get SEO description"""
        if self.meta_description:
            return self.meta_description
        # If not set, use article excerpt
        return self.excerpt
    
    def get_meta_keywords(self):
        """Get SEO keywords"""
        if self.meta_keywords:
            return self.meta_keywords
        # If not set, use tag names
        return ', '.join([tag.name for tag in self.tags.all()])

# templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}My Blog{% endblock %}</title>
    
    <!-- SEO metadata -->
    <meta name="description" content="{% block meta_description %}{% endblock %}">
    <meta name="keywords" content="{% block meta_keywords %}{% endblock %}">
    <meta name="author" content="{% block author %}{% endblock %}">
    
    <!-- Open Graph -->
    <meta property="og:title" content="{% block og_title %}{% endblock %}">
    <meta property="og:description" content="{% block og_description %}{% endblock %}">
    <meta property="og:type" content="article">
    <meta property="og:url" content="{{ request.build_absolute_uri }}">
    
    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary">
    <meta name="twitter:title" content="{% block twitter_title %}{% endblock %}">
    <meta name="twitter:description" content="{% block twitter_description %}{% endblock %}">
    
    <link rel="canonical" href="{{ request.build_absolute_uri }}">
</head>
<body>
    <!-- Page content -->
</body>
</html>

# templates/blog/article_detail.html
{% extends 'base.html' %}

{% block title %}{{ article.title }} - My Blog{% endblock %}

{% block meta_description %}{{ article.get_meta_description }}{% endblock %}

{% block meta_keywords %}{{ article.get_meta_keywords }}{% endblock %}

{% block author %}{{ article.author.get_full_name|default:article.author.username }}{% endblock %}

{% block og_title %}{{ article.title }}{% endblock %}

{% block og_description %}{{ article.get_meta_description }}{% endblock %}

{% block twitter_title %}{{ article.title }}{% endblock %}

{% block twitter_description %}{{ article.get_meta_description }}{% endblock %}

With the implementation of these advanced features, the blog system will have complete user management, rich text editing, performance optimization, and SEO optimization capabilities.

Summary ​

Key points in implementing blog system advanced features:

  1. ✅ Integrate complete user registration, login, and profile management functions
  2. ✅ Integrate rich text editor to enhance content creation experience
  3. ✅ Implement cache optimization strategies to improve system performance
  4. ✅ Implement SEO optimization features to improve search engine visibility
  5. ✅ Focus on user experience and system maintainability

These advanced features make the blog system more complete and professional.

Next Article ​

We will learn about using Django REST Framework.

14.1 Django REST Framework Introduction →

Directory ​

Return to Course Directory

Released under the [BY-NC-ND License](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.en).