作为一名开发者,我最近完成了一个基于Django的个人主页项目,在这个过程中系统学习了Django框架的核心功能。本文将详细分享完整的开发过程,包含所有代码实现和运行结果,希望能帮助正在学习Django的朋友们。

一、项目初始化与环境配置

1. 安装Django

# 安装最新版本的Django
pip install django

# 验证安装
python -m django --version

2. 创建项目

# 创建项目目录
django-admin startproject personal_website

# 进入项目目录
cd personal_website

3. 创建应用

# 创建portfolio应用
python manage.py startapp portfolio

4. 配置应用 在personal_website/settings.py中添加应用:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'portfolio',  # 添加portfolio应用
]

5. 配置媒体文件

# 媒体文件配置
MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / 'media'

二、数据模型设计与实现

1. 定义核心模型 在portfolio/models.py中定义数据模型:

from django.db import models

class PersonalInfo(models.Model):
    """个人信息模型"""
    name = models.CharField(max_length=100, verbose_name='姓名')
    title = models.CharField(max_length=200, verbose_name='职位')
    bio = models.TextField(verbose_name='个人简介')
    email = models.EmailField(verbose_name='邮箱')
    phone = models.CharField(max_length=20, verbose_name='电话')
    wechat = models.CharField(max_length=50, verbose_name='微信')
    avatar = models.ImageField(upload_to='avatars/', blank=True, null=True, verbose_name='头像')
    
    class Meta:
        verbose_name = '个人信息'
        verbose_name_plural = '个人信息'
    
    def __str__(self):
        return self.name

class ResearchDirection(models.Model):
    """研究方向模型"""
    name = models.CharField(max_length=100, verbose_name='研究方向')
    
    class Meta:
        verbose_name = '研究方向'
        verbose_name_plural = '研究方向'
    
    def __str__(self):
        return self.name

class Course(models.Model):
    """课程模型"""
    title = models.CharField(max_length=200, verbose_name='课程名称')
    description = models.TextField(verbose_name='课程描述')
    is_current = models.BooleanField(default=True, verbose_name='当前课程')
    
    class Meta:
        verbose_name = '课程'
        verbose_name_plural = '课程'
    
    def __str__(self):
        return self.title

class Project(models.Model):
    """项目模型"""
    title = models.CharField(max_length=200, verbose_name='项目名称')
    description = models.TextField(verbose_name='项目描述')
    link = models.URLField(blank=True, null=True, verbose_name='项目链接')
    
    class Meta:
        verbose_name = '项目'
        verbose_name_plural = '项目'
    
    def __str__(self):
        return self.title

class BlogPost(models.Model):
    """博客文章模型"""
    title = models.CharField(max_length=200, verbose_name='标题')
    content = models.TextField(verbose_name='内容')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '博客文章'
        verbose_name_plural = '博客文章'
    
    def __str__(self):
        return self.title

2. 数据库迁移

# 创建迁移文件
python manage.py makemigrations

# 执行迁移
python manage.py migrate

3. 创建超级用户

# 创建超级用户(用于后台管理)
python manage.py createsuperuser

三、视图函数与URL配置

1. 编写视图函数 在portfolio/views.py中实现视图:

from django.shortcuts import render
from .models import PersonalInfo, ResearchDirection, Course, Project, BlogPost

def home(request):
    """首页视图"""
    personal_info = PersonalInfo.objects.first()
    research_directions = ResearchDirection.objects.all()
    courses = Course.objects.all()
    projects = Project.objects.all()
    
    context = {
        'personal_info': personal_info,
        'research_directions': research_directions,
        'courses': courses,
        'projects': projects
    }
    return render(request, 'portfolio/home.html', context)

def blog(request):
    """博客页面视图"""
    blog_posts = BlogPost.objects.order_by('-created_at')
    
    context = {
        'blog_posts': blog_posts
    }
    return render(request, 'portfolio/blog.html', context)

2. 配置URL 在portfolio/urls.py中配置应用URL:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('blog/', views.blog, name='blog'),
]

在personal_website/urls.py中包含应用URL:

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('portfolio.urls')),
]

# 添加媒体文件支持
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

四、模板系统与前端实现

1. 创建模板目录

# 创建模板目录结构
mkdir -p portfolio/templates/portfolio

2. 编写首页模板 创建portfolio/templates/portfolio/home.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>个人主页</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        
        header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 40px 0;
            text-align: center;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .header-content {
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
        }
        
        .avatar {
            width: 150px;
            height: 150px;
            border-radius: 50%;
            background-color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 60px;
            margin-bottom: 20px;
        }
        
        .personal-info {
            text-align: center;
        }
        
        .personal-info h1 {
            font-size: 36px;
            margin-bottom: 10px;
        }
        
        .personal-info p {
            font-size: 18px;
            margin-bottom: 20px;
        }
        
        .contact-info {
            display: flex;
            justify-content: center;
            gap: 30px;
            margin-top: 20px;
        }
        
        .contact-item {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        nav {
            background-color: white;
            padding: 20px 0;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            margin-bottom: 30px;
        }
        
        .nav-links {
            display: flex;
            justify-content: center;
            gap: 40px;
        }
        
        .nav-links a {
            color: #333;
            text-decoration: none;
            font-size: 16px;
            font-weight: 500;
            transition: color 0.3s;
        }
        
        .nav-links a:hover {
            color: #667eea;
        }
        
        .section {
            background-color: white;
            padding: 30px;
            margin-bottom: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        
        .section h2 {
            color: #667eea;
            margin-bottom: 20px;
            font-size: 24px;
            border-bottom: 2px solid #667eea;
            padding-bottom: 10px;
        }
        
        .bio {
            font-size: 16px;
            line-height: 1.8;
        }
        
        .research-directions {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            margin-top: 20px;
        }
        
        .direction-tag {
            background-color: #f0f0f0;
            padding: 8px 16px;
            border-radius: 20px;
            font-size: 14px;
        }
        
        .courses {
            margin-top: 20px;
        }
        
        .course-item {
            background-color: #f9f9f9;
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 15px;
        }
        
        .course-item h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .projects {
            margin-top: 20px;
        }
        
        .project-item {
            background-color: #f9f9f9;
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 15px;
        }
        
        .project-item h3 {
            color: #667eea;
            margin-bottom: 10px;
        }
        
        .project-link {
            color: #667eea;
            text-decoration: none;
            font-weight: 500;
        }
        
        .project-link:hover {
            text-decoration: underline;
        }
        
        footer {
            background-color: #333;
            color: white;
            text-align: center;
            padding: 20px 0;
            margin-top: 50px;
        }
    </style>
</head>
<body>
    <header>
        <div class="container header-content">
            <div class="avatar">
                {% if personal_info.avatar %}
                    <img src="{{ personal_info.avatar.url }}" alt="{{ personal_info.name }}" style="width: 100%; height: 100%; border-radius: 50%; object-fit: cover;">
                {% else %}
                    👤
                {% endif %}
            </div>
            <div class="personal-info">
                <h1>{{ personal_info.name }}</h1>
                <p>{{ personal_info.title }}</p>
                <div class="contact-info">
                    <div class="contact-item">
                        📧 {{ personal_info.email }}
                    </div>
                    <div class="contact-item">
                        📱 {{ personal_info.phone }}
                    </div>
                    <div class="contact-item">
                        💬 {{ personal_info.wechat }}
                    </div>
                </div>
            </div>
        </div>
    </header>
    
    <nav>
        <div class="container">
            <div class="nav-links">
                <a href="{% url 'home' %}">首页</a>
                <a href="{% url 'blog' %}">博客</a>
            </div>
        </div>
    </nav>
    
    <div class="container">
        <section class="section">
            <h2>个人简介</h2>
            <div class="bio">
                {{ personal_info.bio|linebreaks }}
            </div>
        </section>
        
        <section class="section">
            <h2>研究方向</h2>
            <div class="research-directions">
                {% for direction in research_directions %}
                    <div class="direction-tag">
                        {{ direction.name }}
                    </div>
                {% endfor %}
            </div>
        </section>
        
        <section class="section">
            <h2>当前课程</h2>
            <div class="courses">
                {% for course in courses %}
                    <div class="course-item">
                        <h3>{{ course.title }}</h3>
                        <p>{{ course.description }}</p>
                    </div>
                {% endfor %}
            </div>
        </section>
        
        <section class="section">
            <h2>项目</h2>
            <div class="projects">
                {% for project in projects %}
                    <div class="project-item">
                        <h3>{{ project.title }}</h3>
                        <p>{{ project.description }}</p>
                        {% if project.link %}
                            <a href="{{ project.link }}" class="project-link" target="_blank">查看项目</a>
                        {% endif %}
                    </div>
                {% endfor %}
            </div>
        </section>
    </div>
    
    <footer>
        <div class="container">
            <p>&copy; {{ personal_info.name }} - 个人主页</p>
        </div>
    </footer>
</body>
</html>

3. 编写博客页面模板 创建portfolio/templates/portfolio/blog.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>博客</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        
        header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 40px 0;
            text-align: center;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .header-content h1 {
            font-size: 36px;
        }
        
        nav {
            background-color: white;
            padding: 20px 0;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            margin-bottom: 30px;
        }
        
        .nav-links {
            display: flex;
            justify-content: center;
            gap: 40px;
        }
        
        .nav-links a {
            color: #333;
            text-decoration: none;
            font-size: 16px;
            font-weight: 500;
            transition: color 0.3s;
        }
        
        .nav-links a:hover {
            color: #667eea;
        }
        
        .section {
            background-color: white;
            padding: 30px;
            margin-bottom: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        
        .section h2 {
            color: #667eea;
            margin-bottom: 20px;
            font-size: 24px;
            border-bottom: 2px solid #667eea;
            padding-bottom: 10px;
        }
        
        .blog-posts {
            margin-top: 20px;
        }
        
        .blog-post {
            background-color: #f9f9f9;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 20px;
            transition: transform 0.3s, box-shadow 0.3s;
        }
        
        .blog-post:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        
        .blog-post h3 {
            color: #667eea;
            margin-bottom: 10px;
            font-size: 20px;
        }
        
        .blog-post .date {
            color: #999;
            font-size: 14px;
            margin-bottom: 15px;
        }
        
        .blog-post .content {
            font-size: 16px;
            line-height: 1.8;
        }
        
        footer {
            background-color: #333;
            color: white;
            text-align: center;
            padding: 20px 0;
            margin-top: 50px;
        }
    </style>
</head>
<body>
    <header>
        <div class="container header-content">
            <h1>博客</h1>
        </div>
    </header>
    
    <nav>
        <div class="container">
            <div class="nav-links">
                <a href="{% url 'home' %}">首页</a>
                <a href="{% url 'blog' %}">博客</a>
            </div>
        </div>
    </nav>
    
    <div class="container">
        <section class="section">
            <h2>博客文章</h2>
            <div class="blog-posts">
                {% for post in blog_posts %}
                    <div class="blog-post">
                        <h3>{{ post.title }}</h3>
                        <div class="date">发布于: {{ post.created_at|date:"Y-m-d H:i" }}</div>
                        <div class="content">
                            {{ post.content|linebreaks }}
                        </div>
                    </div>
                {% empty %}
                    <p>暂无博客文章</p>
                {% endfor %}
            </div>
        </section>
    </div>
    
    <footer>
        <div class="container">
            <p>&copy; 博客页面</p>
        </div>
    </footer>
</body>
</html>

五、后台管理配置

1. 注册模型到后台 在portfolio/admin.py中注册模型:

from django.contrib import admin
from .models import PersonalInfo, ResearchDirection, Course, Project, BlogPost

admin.site.register(PersonalInfo)
admin.site.register(ResearchDirection)
admin.site.register(Course)
admin.site.register(Project)
admin.site.register(BlogPost)

六、运行项目

1. 启动开发服务器

# 启动开发服务器
python manage.py runserver

2. 访问项目

七、运行成功的图片位置

个人主页截图 

八、项目优化与扩展

1. 性能优化

  • 使用select_related和prefetch_related减少数据库查询
  • 配置缓存系统
  • 优化静态文件加载

2. 功能扩展

  • 添加用户认证系统
  • 实现评论功能
  • 添加搜索功能
  • 集成第三方服务(如社交媒体分享)

3. 部署建议

  • 使用Gunicorn或uWSGI作为WSGI服务器
  • 配置Nginx作为反向代理
  • 使用PostgreSQL或MySQL作为生产数据库
  • 配置HTTPS

九、总结

通过这个个人主页项目,我系统地学习了Django的核心功能,包括:

  • 项目结构和配置管理
  • 数据模型设计与数据库操作
  • 视图函数和URL路由
  • 模板系统和前端渲染
  • 后台管理系统
  • 媒体文件处理

Django的"batteries included"理念让我能够快速构建功能完整的Web应用,而不需要从零开始实现所有组件。同时,Django的文档和社区支持也让学习过程变得更加顺畅。

这个项目不仅是一个展示个人信息的平台,也是我学习Django的实践成果。通过不断完善和扩展这个项目,我可以进一步提升自己的Web开发能力。

希望本文的详细代码和实现过程能够对正在学习Django的朋友们有所帮助。如果有任何问题或建议,欢迎在评论区留言交流!


项目地址: https://gitcode.com/gcw_NAormESZ/DJango_personal_web.git

技术栈:

  • Python 3.14
  • Django 6.0.3
  • HTML5/CSS3
  • SQLite(开发环境)

功能特性:

  • 动态个人主页
  • 博客系统
  • 后台管理
  • 响应式设计
  • 媒体文件支持
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐