Python Web应用框架Django编程笔记

243次阅读
没有评论

共计 8256 个字符,预计需要花费 21 分钟才能阅读完成。

安装

pip install django

安装完,在 Python 安装目录 Libsite-packages 下会多一个文件夹 django(框架源码),在 Scripts 文件夹下会多一个文件 django-admin.exe(用来创建 django 项目)。

创建项目

打开终端,进入某个目录(项目路径),执行命令创建项目:django-admin startproject mysite

运行后将在目录下生成一个 mysite 目录,也就是 Django 项目的根目录。

创建应用

在 Django 中,每一个应用(app)都是一个 Python 包。

cd mysite
python manage.py startapp app

运行后会自动生成 app 文件夹:

app
|   admin.py    # Django 默认提供 admin 后台管理
|   apps.py     # app 启动类
|   models.py   # 对数据库操作
|   tests.py    # 单元测试
|   views.py    # 视图函数
|   __init__.py
|
---migrations  # 数据框变更记录
        __init__.py

注册应用

打开mysite/setting.py,在 INSTALLED_APPS 当中注册 app 模块:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app',
]

设置

时区和语言

修改项目的 settings.py 文件如下:

LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False

admin 后台

设置 admin 后台应用显示为中文,需要修改应用目录下的 apps.py 文件:

class LoginConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'login'
    verbose_name = '用户管理' # 新增

设置 admin 后台首页的网页标题,需要修改应用目录下的的 admin.py 文件:

admin.site.site_title = '后台管理' # 修改标题
admin.site.site_header = '后台管理' # 修改 header

本地配置

首先创建自己的本地配置文件:local_settings.py。在 settings.py 中导入:

try:
    from .local_settings import *
except ImportError:
    pass

切记:给别人代码时,不要给local_settings.py

快速上手

URL 和视图配置

打开mysite/urls.py,修改为:

from django.contrib import admin
from django.urls import path

from app import views  # 导入 views

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

    # 域名 /index/ -> index 函数,即绑定 URL 与视图函数
    path('index/', views.index),
]

编写视图函数

视图,即具体的业务代码,打开app/views.py,修改为:

from django.shortcuts import render, HttpResponse

def index(requests):
    return HttpResponse('欢迎使用')

启动项目

命令行启动

python manage.py runserver

Django 的服务器默认运行在 8000 端口,如果想指定端口,命令如下:

python manage.py runserver 8080

templates 模板

在 app 文件夹下新建 templates 文件夹,然后在 templates 文件夹下新建文件user_list

在文件 mysite/urls.py 中添加 URL:

path('user/list', views.user_list, {'name': '李小龙'}),

在文件 app/views.py 中添加函数:

def user_list(request):
    # 去 app 目录下的 templates 目录寻找 user_list
    return render(request, 'user_list')

静态文件

在 app 文件夹下新建 static 文件夹,然后在 static 目录下创建 css 目录,js 目录,img 目录,plugin 目录,分别放 css 文件,js 文件,图片和插件。

在模板中使用需要加入 {% load static %} 代码,以下实例从静态目录中引入图片,修改 user_list 为:

{% load static %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title> 用户列表 </title>
</head>
<body>
    <h1>{{name}}</h1>
    <img src="{% static 'img/logo.webp' %}" alt="logo">
</body>
</html>

模板语法

本质上是在 html 中写一些占位符,由数据对这些占位符进行替换和处理。

变量相关

在文件 mysite/urls.py 中添加 URL:

path('tpl/', views.tpl),

在文件 app/views.py 中添加函数:

def tpl(request):
    name = '李小龙'
    roles = ['管理员', 'CEO', '保安']
    user_info = {'name': " 李小龙 ", 'sex': '女', 'role': '保安'}
    return render(request, 'tpl', {'n1': name, 'n2': roles, 'n3': user_info})

render 使用了一个字典作为参数,字典中元素的键值 n1 对应了模板中的变量 {{n1}}。

app/templates 目录下新建 tpl 文件,代码如下:

<h1>{{n1}}</h1>
<h1>{{n2}}</h1>
<h1>{{n2.0}}</h1>
<h1>{{n2.1}}</h1>
<h1>{{n3.name}}</h1>
<h1>{{n3.sex}}</h1>

访问 http://127.0.0.1:8000/tpl/,查看页面输出结果。

逻辑相关

tpl 文件添加如下代码:

<hr/>
<div>
    {% for item in n2 %}
        <span>{{item}}</span>
    {% endfor %}
</div>
<hr/>
<ul>
    {% for k,v in n3.items %}
        <li>{{k}} = {{v}}</li>
    {% endfor %}
</ul>

访问 http://127.0.0.1:8000/tpl/,查看页面输出结果。

模板继承

父模板

{% block 名称 %}
预留给子模板的区域,可以设置默认内容
{% endblock 名称 %}

子模板

{% extends " 父模板路径 " %}

子模板使用标签 extends 继承父模板。

接下来在 templates 目录中添加 base 文件,代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> 编程笔记 </title>
</head>
<body>
    <h1>Hello World!</h1>
    <p> 编程笔记 Django 测试。</p>
    {% block mainbody %}
       <p>original</p>
    {% endblock %}
</body>
</html>

index 继承 base,index 修改后的代码如下:

{%extends "base" %}

{% block mainbody %}
<p> 继承了 base 文件。</p>
{% endblock %}

访问 http://127.0.0.1:8000/index 查看页面输出结果。可以看到,这里相同名字的 block 标签用于替换 base 的相应 block。

请求和响应

在文件 mysite/urls.py 中添加 URL:

path('something/', views.something),

在文件 app/views.py 中添加函数:

from django.shortcuts import redirect
def something(request):
    # 获取请求方式 GET/POST
    print(request.method)

    # 在 url 传递值 /something/?n1= 李小龙
    print(request.GET)

    # 在请求体中提交数据
    print(request.POST)

    # 重定向
    return redirect('https://www.baidu.com/')

访问 http://127.0.0.1:8000/something/,查看页面输出结果。

Django 模型

MySQL 是 Web 应用中最常用的数据库,这里以 MySQL 作为实例进行介绍。如果没安装 mysql 驱动,执行以下命令安装:

pip3 install pymysql

这里作个说明,pymysql 和 mysqlclient 是目前 Python 连接 MySQL 的主流方式。

区别是:mysqlclient 速度比 pymysql 快;pymysql 更加简单易使用。

如果是大型项目,当然是用 mysqlclient,该驱动性能比较优异;中小项目用 pymysql 就可以了,毕竟是使用 Python 写的,契合度更高。

数据库配置

在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:

DATABASES = { 
    'default': 
    { 
        'ENGINE': 'django.db.backends.mysql', # 数据库引擎
        'NAME': 'django', # 数据库名称
        'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址
        'PORT': 3306, # 端口 
        'USER': 'root', # 数据库用户名
        'PASSWORD': '', # 数据库密码
    }  
}

接下来,告诉 Django 使用 pymysql 模块连接 mysql 数据库:

## 在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置
import pymysql
pymysql.install_as_MySQLdb()

操作表

创建表

在 models.py 文件中:

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    # 设置默认值
    age = models.IntegerField(default=0)
    # 允许为空
    data = models.DateField(null=True, blank=True)

执行命令:

## 创建应用的迁移数据文件
python manage.py makemigrations app
## 生成数据库表
python manage.py migrate

修改表

在文件 urls.py 中添加 URL:

path('orm/', views.orm),

在文件 views.py 中添加函数:

def orm(request):
    # 新增
    UserInfo.objects.create(name='李小龙', age=18, date='2022-04-04')

    # 删除
    # UserInfo.objects.filter(id=1).delete()
    # UserInfo.objects.all().delete()

    # 查询数据,data_list 是 QuerySet 类型
    # data_list = UserInfo.objects.all()
    # for obj in data_list:
    #     print(obj.name, obj.age, obj.date)
    # 获取第一条数据
    # row_obj = UserInfo.objects.filter(id=5).first()
    # print(row_obj.id, row_obj.name)

    # 更新数据
    # UserInfo.objects.all().update(age=20)
    # UserInfo.objects.filter(id=5).update(age=20)

    return HttpResponse('成功')

访问 http://127.0.0.1:8000/orm/,查看页面输出结果。

外键删除

一个模型如果使用了外键,那么在对方那个模型被删掉后,该进行什么样的操作,可通过 on_delete 来指定。指定的类型如下:

  • CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除
  • PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。如果我们强行删除,Django 就会报错
  • SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空
  • SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。
  • SET():如果外键的那条数据被删除了,那么将会获取 SET 函数中的值来作为这个外键的值。SET 函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。可以不用指定默认值
  • DO_NOTHING:不采取任何行为。一切全看数据库级别的约束

数据库接口

QuerySet 是 Django 提供的强大的数据库接口(API)。从数据库中查询得到的结果一般是一个集合,这个集合叫做 QuerySet。

QuerySet 惰性

所谓惰性,就是不会主动去执行。创建 QuerySet 的行为(语句)不会马上执行 sql,而是返回一个 QuerySet(查询结果集对象),只有在调用 QuerySet 的时候才会涉及到数据库操作。

QuerySet 缓存

下例中例 1 比例 2 要好,因为在你打印文章标题后,Django 不仅执行了查询,还把查询到的 article_list 放在了缓存里,因此这个 article_list 是可以复用的。例 2 就不行了。

## Example 1: Good
article_list = Article.objects.filter(title_contains="django")
for article in article_list:
    print(article.title)

## Example 2: Bad
for article in Article.objects.filter(title_contains="django"):
    print(article.title)

在 loop 前加个 if 判断,防止 article_list 是个空数据集:

article_list = Article.objects.filter(title_contains="django")
if article_list:
    for article in article_list:
        print(article.title)
else:
    print("No records")

如果只是希望了解查询的结果是否存在,而不需要使用整个数据集,这时 if 触发整个 queryset 的缓存变成了一件坏事情。这时可以用 exists()方法。与 if 判断不同,exists 只会检查查询结果是否存在,返回 True 或 False,而不会缓存 article_list。

article_list = Article.objects.filter(title_contains="django")
if article_list.exists():
    print("Records found.")
else:
    print("No records")

统计查询结果数量

len()与 count()均能统计查询结果的数量。一般来说 count 更快,因为它是从数据库层面直接获取查询结果的数量,而不是返回整个数据集,而 len 会导致 queryset 的执行,需要将整个 queryset 载入内存后才能统计其长度。但事情也没有绝对,如果数据集 queryset 已经在缓存里了,使用 len 更快,因为它不需要跟数据库再次打交道。

下面三个例子中,只有例 2 最差,尽量不要用:

## Example 1: Good
count = Article.objects.filter(title_contains="django").count()

## Example 2:Bad
count = Article.objects.filter(title_contains="django").len()

## Example 3: Good
article_list = Article.objects.filter(title_contains="django")
if article_list:
    print("{} records found.".format(article_list.len()))

按需查询数据

当查询到的 queryset 非常大时,会大量占用内存(缓存)。我们可以使用 values 和 value_list 方法按需提取数据。

article_list = Article.objects.filter(title_contains="django").values('title')
if article_list:
    print(article.title)

article_list = Article.objects.filter(title_contains="django").values_list('id', 'title')
if article_list:
    print(article.title)

还可以使用 defer 和 only 这两个查询方法来实现按需查询数据。

defer 方法

defer 方法的用途是查询数据库时跳过指定的字段,防止不要的字段载入内存,从而节省空间:

## 查询时跳过 id 和 title 字段
Article.objects.defer('id', 'title')

该方法可以和 filter, exclude 方法联用,其顺序无关紧要,如下所示:

Article.objects.defer(‘id’).filter(title_contains=”django”).defer(‘title’)

only 方法

only 方法与 defer 方法作用类似,只不过 only 方法是指定需要载入的字段。比如下面查询将只会载入 id 和 title。

Article.objects.only('id', 'title')

使用 only 方法要注意它的顺序,它的执行以最后一个为准。下例将只会载入 pub_date:

Article.objects.only('id', 'title').only('pub_date')

only 方法与 defer 方法可以联用,但要注意先后顺序。下例只会载入 title:

Article.objects.only('id', 'title').defer('id')

更新数据库

更新部分字段

更新数据库部分字段更好的方式是用 update,而不是 save 方法。

## Example 1: Good
Article.objects.filter(id=10).update(title='Django')

## Example 2: Bad
article = Article.objects.get(id=10)
Article.title = "Django"
article.save()
批量创建或更新数据

Django 提供的 bulk_create 和 bulk_update 方法可以一次添加或更新多条数据,效率要高很多,如下所示:

## 内存生成多个对象实例
articles = [Article(title="title1", body="body1"), Article(title="title2", body="body2"), Article(title="title3", body="body3")]

## 执行一次 SQL 插入数据
Article.objects.bulk_create(articles)

命令

## 创建超级管理员
python manage.py createsuperuser
## 无需启动 Django 操作数据库中某个表的数据
python manage.py shell

正文完
 0
阿伯手记
版权声明:本站原创文章,由 阿伯手记 于2023-08-13发表,共计8256字。
转载说明:本站原创内容,除特殊说明外,均基于 CC BY-NC-SA 4.0 协议发布,转载须注明出处与链接。
评论(没有评论)
验证码

阿伯手记

阿伯手记
阿伯手记
喜欢编程,头发渐稀;成长路上,宝藏满地
文章数
766
评论数
204
阅读量
446498
今日一言
-「
热门文章
职场救急!AI请假话术生成器:1秒定制高通过率理由

职场救急!AI请假话术生成器:1秒定制高通过率理由

超级借口 不好开口?借口交给我!智能生成工作请假、上学请假、饭局爽约、约会拒绝、邀约推辞、万能借口等各种借口理...
夸克网盘快传助手提高非VIP下载速度

夸克网盘快传助手提高非VIP下载速度

夸克网盘限速这个大家都知道,不开会员差不多限速在几百 K。那有没有办法在合法合规途径加速下载夸克网盘呢?这里推...
国内已部署DeepSeek模型第三方列表 免费满血版联网搜索

国内已部署DeepSeek模型第三方列表 免费满血版联网搜索

本文收集了目前国内已部署 DeepSeek 模型的第三方列表,个个都是免费不限次数的满血版 DeepSeek,...
巴别英语:用美剧和TED演讲轻松提升英语听力与口语

巴别英语:用美剧和TED演讲轻松提升英语听力与口语

还在为枯燥的英语学习而烦恼吗?巴别英语通过创新的美剧学习模式,让英语学习变得生动有趣。平台提供海量美剧和 TE...
Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 是一款在线中文姓名生成器,可在几秒内生成符合个人需求的中文名字。...
TVAPP:开源电视盒子资源库,一键打造家庭影院

TVAPP:开源电视盒子资源库,一键打造家庭影院

导语 TVAPP 是一个专为 Android TV 电视盒子用户打造的开源影音资源库,集成了影视、直播、游戏等...
2025年12月 每日精选

2025年12月 每日精选

关于每日精选栏目 发现一些不错的资源,点击 这里 快速投稿。 12 月 26 日 .ax 顶级域 目前全球唯一...
最新评论
15220202929 15220202929 怎么用
八对 八对 麻烦大佬更新下【堆新】的友链站名:八对星星描述:极目星视穹苍无界•足履行者大地有疆链接:https://8dui.com图标:https://cf.8dui.com/logo.webp横标:https://cf.8dui.com/logo-w.webp订阅:https://8dui.com/rss.xml
三毛笔记 三毛笔记 已添加
DUINEW DUINEW 已添加贵站,期待贵站友链~博客名称:堆新博客地址:https://duinew.com/博客描述:堆新堆新,引力向新!——堆新(DUINEW)博客头像:https://d.duinew.com/logo.webp横版头像:https://d.duinew.com/logo-w.webp博客订阅:https://duinew.com/rss.xml
hedp hedp 没看懂
bingo bingo 直接生成就可以啦,也可以添加一些选项
满心 满心 申请更新下友联信息,原名:满心记,现名:周天记原域名:qq.mba,现域名:zhoutian.com描述:我在人间混日子
开业吉日 开业吉日 没看明白这个怎么用
开业吉日 开业吉日 beddystories 这个网站太赞了,收藏
热评文章
夸克网盘快传助手提高非VIP下载速度

夸克网盘快传助手提高非VIP下载速度

夸克网盘限速这个大家都知道,不开会员差不多限速在几百 K。那有没有办法在合法合规途径加速下载夸克网盘呢?这里推...
清华大学官方免费DeepSeek教程

清华大学官方免费DeepSeek教程

AI 领域近期最引人注目的焦点当属 DeepSeek,这款由中国创新企业深度求索研发的人工智能工具,正以开放源...
Short-Link 免费开源短网址程序,基于Fastify、Vercel和Supabase构建

Short-Link 免费开源短网址程序,基于Fastify、Vercel和Supabase构建

Short-Link 是一款基于 Fastify、Vercel 和 Supabase 构建的 URL 缩短服务...
国内已部署DeepSeek模型第三方列表 免费满血版联网搜索

国内已部署DeepSeek模型第三方列表 免费满血版联网搜索

本文收集了目前国内已部署 DeepSeek 模型的第三方列表,个个都是免费不限次数的满血版 DeepSeek,...
Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 是一款在线中文姓名生成器,可在几秒内生成符合个人需求的中文名字。...
BeddyStories 完全免费儿童睡前故事库,让孩子随时随地入睡更轻松

BeddyStories 完全免费儿童睡前故事库,让孩子随时随地入睡更轻松

BeddyStories 是一个致力于为儿童提供优质睡前故事的在线平台,用户可以在这里找到来自世界各地的经典故...
DrawLink:一键生成链接视觉卡片,提升分享点击率

DrawLink:一键生成链接视觉卡片,提升分享点击率

小贴士 :此站或已变迁,但探索不止步。我们已为您备好「类似网站」精选合集,相信其中的发现同样能为您带来惊喜。