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后台应用显示为中文,需要修改应用目录下的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。
打开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
在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/')</code></pre><p>访问 <code>http://127.0.0.1:8000/something/</code>,查看页面输出结果。</p><h2>Django模型</h2><p>MySQL 是 Web 应用中最常用的数据库,这里以 MySQL 作为实例进行介绍。如果没安装 mysql 驱动,执行以下命令安装:</p><pre><code>pip3 install pymysql</code></pre><p>这里作个说明,pymysql和mysqlclient是目前Python连接MySQL的主流方式。</p><p>区别是:mysqlclient速度比pymysql快;pymysql更加简单易使用。</p><p>如果是大型项目,当然是用mysqlclient,该驱动性能比较优异;中小项目用pymysql就可以了,毕竟是使用Python写的,契合度更高。</p><h3>数据库配置</h3><p>在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:</p><pre><code>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('成功')</code></pre><p>访问 <code>http://127.0.0.1:8000/orm/</code>,查看页面输出结果。</p><h3>外键删除</h3><p>一个模型如果使用了外键,那么在对方那个模型被删掉后,该进行什么样的操作,可通过on_delete来指定。指定的类型如下:</p><ul><li>CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除</li><li>PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。如果我们强行删除,Django就会报错</li><li>SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空</li><li>SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。</li><li>SET():如果外键的那条数据被删除了,那么将会获取SET函数中的值来作为这个外键的值。SET函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。可以不用指定默认值</li><li>DO_NOTHING:不采取任何行为。一切全看数据库级别的约束</li></ul><h3>数据库接口</h3><p>QuerySet是Django提供的强大的数据库接口(API)。从数据库中查询得到的结果一般是一个集合,这个集合叫做 QuerySet。</p><h4>QuerySet惰性</h4><p>所谓惰性,就是不会主动去执行。创建 QuerySet 的行为(语句)不会马上执行sql,而是返回一个QuerySet(查询结果集对象),只有在调用QuerySet的时候才会涉及到数据库操作。</p><h4>QuerySet缓存</h4><p>下例中例1比例2要好,因为在你打印文章标题后,Django不仅执行了查询,还把查询到的article_list放在了缓存里,因此这个article_list是可以复用的。例2就不行了。</p><pre><code>## 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方法的用途是查询数据库时跳过指定的字段,防止不要的字段载入内存,从而节省空间:
## 查询时跳过id和title字段 Article.objects.defer('id', 'title')
该方法可以和filter, exclude方法联用,其顺序无关紧要,如下所示:
Article.objects.defer('id').filter(title_contains="django").defer('title')
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
本文作者:a
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!