Django入门教程:搭建你的第一个Python网站

开发者晨报
2025-12-17 15:08
阅读 452

上周五晚上,我正坐在深圳南山科技园的工位上,盯着屏幕上凌晨三点的部署日志发呆。隔壁组的产品经理刚刚提了个“小需求”——做一个内部数据展示页,用来监控我们每天爬取的百万级商品信息。我心想,不就是个前端页面嘛,但转念一想,我们后端全是Java栈,Spring Boot + MyBatis 配得整整齐齐,临时加个展示服务?别闹了,光是启动时间就能把我熬到天亮。

就在这时,我想起了Django——这个被我们DBA圈子里私下称为“全栈懒人神器”的Python框架。虽然我是个从Oracle时代摸爬滚打过来的老DBA,后来转做后端开发,对数据库有执念到连JSON字段都要建索引那种,但不得不说,Django在快速原型开发上的表现,真香。

为什么选Django?别跟我说Java!

我知道,很多Java老铁看到Python就皱眉:“性能不行”、“动态类型太危险”、“上线出问题谁背锅?”——这些我都懂。我自己也维护过几个高并发的Java服务,GC调优、线程池配置、连接池参数,哪一样不是血泪史?

但兄弟们,工具要分场景用。你总不能拿电焊枪去修手表吧?

这次的需求很简单:把MySQL里已经爬好的商品数据(没错,是我们自己写的爬虫抓的)通过一个网页展示出来,支持基本搜索和分页。没复杂业务逻辑,没高并发要求(顶多十个运营同事同时看),甚至不需要用户登录。这种场景下,用Spring Boot从零搭一套CRUD,还要配Thymeleaf或者前后端分离再搞个Vue,属实是杀鸡用牛刀。

而Django呢?自带ORM、Admin后台、路由、模板引擎,开箱即用。更重要的是——它对数据库的操作非常“尊重”。作为一个DBA出身的人,我特别看重这一点:Django ORM生成的SQL虽然不是最高效的,但它不会胡乱JOIN,不会N+1查询(只要你注意点),而且migration机制让我能清晰追踪每一次表结构变更。这比某些ORM动不动就SELECT * 强太多了。

动手!从零开始搭个站

环境准备

首先确保你装了Python(建议3.8+),然后:

pip install django

创建项目:

django-admin startproject myshop
cd myshop
python manage.py startapp products

这时候目录结构大概是这样:

myshop/
├── manage.py
├── myshop/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── products/
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── models.py
    ├── tests.py
    └── views.py

数据库设计:DBA的执念时刻

我们的商品数据来自爬虫,字段大概有:title, price, category, source_url, created_at。作为DBA,我第一反应不是写代码,而是想索引怎么建

products/models.py 中定义模型:

from django.db import models

class Product(models.Model):
    title = models.CharField(max_length=255, db_index=True)  # 标题常用于搜索,加索引
    price = models.DecimalField(max_digits=10, decimal_places=2)
    category = models.CharField(max_length=100, db_index=True)  # 分类筛选也常用
    source_url = models.URLField(unique=True)  # 爬虫去重靠这个
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        db_table = 'product'  # 明确指定表名,DBA习惯
        ordering = ['-created_at']  # 默认按时间倒序

注意:我特意给 titlecategorycreated_at 加了 db_index=True。因为在实际使用中,运营肯定要按分类筛选、按时间排序、按关键词搜标题。没有索引?等数据量上来,页面加载5秒起步,产品经理又要半夜打电话问“是不是数据库挂了”。

然后生成并执行迁移:

python manage.py makemigrations
python manage.py migrate

这条命令会自动生成SQL并在数据库里建表。你可以用 --sql 参数看看它到底干了啥:

python manage.py sqlmigrate products 0001

输出类似:

CREATE TABLE `product` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `title` varchar(255) NOT NULL,
    `price` numeric(10, 2) NOT NULL,
    ...
);
CREATE INDEX `product_title_idx` ON `product` (`title`);
...

看到没?索引名都给你规范好了。这种可控性,让我这个前DBA感到安心。

快速接入已有数据:爬虫成果不浪费

我们的爬虫是用Scrapy写的,数据已经存在MySQL里。Django ORM可以直接读,但要注意两点:

  1. 字段类型匹配(比如爬虫存的是字符串价格,这里要用Decimal)
  2. 主键是否一致

如果表已经存在,可以用 python manage.py inspectdb 自动生成模型,然后手动调整。

不过为了演示,我们就假装数据是Django自己插入的。你可以在 python manage.py shell 里手动加几条:

from products.models import Product
Product.objects.create(
    title="iPhone 15",
    price=5999.00,
    category="手机",
    source_url="https://example.com/iphone15"
)

写个视图:别怕前端

很多后端(包括曾经的我)看到“前端”两个字就头大。但Django的模板系统真的很轻量。

先在 products/views.py 里写个简单视图:

from django.shortcuts import render
from .models import Product

def product_list(request):
    query = request.GET.get('q')
    category = request.GET.get('category')
    
    products = Product.objects.all()
    
    if query:
        products = products.filter(title__icontains=query)
    if category:
        products = products.filter(category=category)
    
    # 分页很重要!不然10万条数据一次查出来,DB直接躺平
    from django.core.paginator import Paginator
    paginator = Paginator(products, 20)  # 每页20条
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    return render(request, 'products/list.html', {'page_obj': page_obj})

然后在 templates/products/list.html 写模板(记得在 settings.py 里配置 TEMPLATES 路径):

<!DOCTYPE html>
<html>
<head>
    <title>商品列表</title>
</head>
<body>
    <form method="get">
        <input type="text" name="q" value="{{ request.GET.q }}" placeholder="搜索标题">
        <select name="category">
            <option value="">全部分类</option>
            <!-- 这里可以动态加载分类,简化起见写死 -->
            <option value="手机">手机</option>
            <option value="电脑">电脑</option>
        </select>
        <button type="submit">搜索</button>
    </form>

    <ul>
    {% for product in page_obj %}
        <li>{{ product.title }} - ¥{{ product.price }} ({{ product.category }})</li>
    {% endfor %}
    </ul>

    <!-- 分页导航 -->
    <div class="pagination">
        {% if page_obj.has_previous %}
            <a href="?page=1">&laquo; 首页</a>
            <a href="?page={{ page_obj.previous_page_number }}">上一页</a>
        {% endif %}

        <span>第 {{ page_obj.number }} 页,共 {{ page_obj.paginator.num_pages }} 页</span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">下一页</a>
            <a href="?page={{ page_obj.paginator.num_pages }}">末页 &raquo;</a>
        {% endif %}
    </div>
</body>
</html>

最后在 myshop/urls.pyproducts/urls.py 里配路由(略,标准操作)。

跑起来:

python manage.py runserver

访问 http://127.0.0.1:8000/products/,搞定!

生产环境?别慌,DBA来兜底

当然,上面只是本地开发。真要上线,还得考虑:

  • 数据库连接池:Django默认没连接池,高并发下会频繁创建销毁连接。建议用 django-db-geventpool 或者前面加个PgBouncer(如果你用PostgreSQL)。
  • 静态文件:开发时Django能serve static,但生产必须用Nginx。
  • 安全DEBUG=False,设置 ALLOWED_HOSTS,别把admin后台暴露出去。
  • 性能:如果数据量大,记得用 select_related / prefetch_related 优化查询,避免N+1。

我们团队上线时就踩过坑:有一次忘了关DEBUG,结果某个页面报错直接把数据库密码打印出来了……运维大哥差点把我祭天。

对比一下:Django vs Spring Boot 做同样事情

维度 Django Spring Boot
启动速度 几秒 10s+(带JVM)
代码量 ~50行核心逻辑 ~200行(含配置类)
数据库操作 ORM简洁,SQL可控 MyBatis需手写SQL或XML
前端集成 内置模板,快速渲染 通常前后端分离,需额外搭前端
学习曲线 Python基础即可 需理解Spring生态
适合场景 内部工具、MVP、数据展示 高并发、复杂业务系统

所以,别一上来就说“我们公司全是Java,不用Python”。技术选型要看需求,不是看信仰

最后说两句

其实我写这篇教程,是因为上周有个实习生问我:“哥,我想做个个人博客,该用啥?” 我脱口而出:“Django啊!” 他一脸疑惑:“不是应该学Spring Cloud Alibaba全家桶吗?”

我笑了。年轻人,等你经历过双11凌晨三点排查慢SQL,经历过因为一个N+1查询导致数据库CPU 100%,你就会明白——有时候,简单就是最大的优雅

Django可能不适合做交易核心系统,但它绝对是快速验证想法、搭建内部工具、展示爬虫成果的最佳拍档。尤其对我们这种对数据库有执念的人来说,它既给了你便利,又没剥夺你对数据的控制权。

好了,教程就到这里。我要回去继续盯着我的Java服务了——毕竟,明天又是需求评审日,产品经理说要加个“智能推荐”功能……

(完)

P.S. 如果你也是DBA转后端,或者对数据库有莫名执念,欢迎留言交流。顺便求问:有没有人用Django + ClickHouse 做实时分析的?我们正在考虑替换部分MySQL聚合查询……

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝