一、Django框架简介
Django框架是Python的常用web框架,遵循 MVC 设计模式的框架,采用了MTV的框架模式,即模型M,视图V和模版T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。并于2005年7月在BSD许可证下发布。这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的。
2019年12月2日,Django 3. 0发布 。
核心组件:
- ORM:用于创建模型的对象关系映射;
- 为最终用户设计较好的管理界面;
- URL 设计;
- 设计者友好的模板语言;
- 缓存系统。
二、安装Django框架
直接通过pip安装,安装虚拟机之后,可以安装到虚拟机中。
pip install django
E:\>cd E:\Zero.Apps\Python.Demo
E:\Zero.Apps\Python.Demo>virtualenv zero.demo.venv
created virtual environment CPython3.8.6.final.0-64 in 5946ms
creator CPython3Windows(dest=E:\Zero.Apps\Python.Demo\zero.demo.venv, clear=False, no_vcs_ignore=False, global=False)
seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\lin_j\AppData\Local\pypa\virtualenv)
added seed packages: pip==23.1.2, setuptools==68.0.0, wheel==0.40.0
activators BashActivator,BatchActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
E:\Zero.Apps\Python.Demo>cd zero.demo.venv
E:\Zero.Apps\Python.Demo\zero.demo.venv>Scripts\activate
(zero.demo.venv) E:\Zero.Apps\Python.Demo\zero.demo.venv>pip django
ERROR: unknown command "django"
(zero.demo.venv) E:\Zero.Apps\Python.Demo\zero.demo.venv>pip install django
Collecting django
Downloading Django-4.2.3-py3-none-any.whl (8.0 MB)
---------------------------------------- 8.0/8.0 MB 20.4 MB/s eta 0:00:00
Collecting asgiref<4,>=3.6.0 (from django)
Downloading asgiref-3.7.2-py3-none-any.whl (24 kB)
Collecting sqlparse>=0.3.1 (from django)
Downloading sqlparse-0.4.4-py3-none-any.whl (41 kB)
---------------------------------------- 41.2/41.2 kB 1.9 MB/s eta 0:00:00
Collecting backports.zoneinfo (from django)
Downloading backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl (38 kB)
Collecting tzdata (from django)
Downloading tzdata-2023.3-py2.py3-none-any.whl (341 kB)
---------------------------------------- 341.8/341.8 kB 22.1 MB/s eta 0:00:00
Collecting typing-extensions>=4 (from asgiref<4,>=3.6.0->django)
Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB)
Installing collected packages: tzdata, typing-extensions, sqlparse, backports.zoneinfo, asgiref, django
Successfully installed asgiref-3.7.2 backports.zoneinfo-0.2.1 django-4.2.3 sqlparse-0.4.4 typing-extensions-4.7.1 tzdata-2023.3
[notice] A new release of pip is available: 23.1.2 -> 23.2
[notice] To update, run: python.exe -m pip install --upgrade pip
三、创建Django项目
3.1 创建一个Django项目
django-admin startproject projectname
在要创建项目的目录文件夹下用指令创建项目,根据输入的名字即可创建对应的django项目。
注意:项目名不能含有".",但是可以含有下划线。若使用虚拟环境,需要在虚拟环境下进行创建项目。
# 在虚拟环境下创建
(zero.demo.venv) PS D:\Zero.App\Python.Demo> django-admin startproject "ZeroDjangoDemo"
(zero.demo.venv) PS D:\Zero.App\Python.Demo>
创建项目后可以查看到项目的基本文件夹信息:
3.2 运行程序
python manage.py runserver
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
July 20, 2023 - 14:12:13
Django version 4.2.3, using settings 'ZeroDjangoDemo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[20/Jul/2023 14:13:18] "GET / HTTP/1.1" 200 10664
Not Found: /favicon.ico
[20/Jul/2023 14:13:18] "GET /favicon.ico HTTP/1.1" 404 2118
需要切换到项目文件夹中,然后运行命令启动框架服务。
启动后,可以通过127.0.0.1:8000访问前台网页,提示创建项目成功:
3.3 数据迁移
python manage.py migrate
PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
PS D:\Zero.App\Python.Demo\ZeroDjangoDemo>
同样需要在项目文件夹下创建。
3.4 创建超级管理员
python manage.py createsuperuser
PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py createsuperuser
Username (leave blank to use 'ljm'): zero
Email address:
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: n
Password:
Password (again):
Superuser created successfully.
创建超级管理,注意输入密码的时候不能与邮箱一致,也不能位数太小,要求大于8位字符。
创建后,可以通过admin访问后台:
输入超级管理员和密码后即可访问。
3.5 项目模板文件简介
文件 | 说明 |
---|---|
settings.py | Django的配置文件,配置具体的项目信息 |
urls.py | Django的路由文件,配置访问的路径和对应的函数 |
wsgi.py | Django的WSGI接口设置文件 |
manage.py | Django的入口文件 |
四、创建APP
4.1 创建APP
DJango项目中,推荐使用APP实现不同的模块功能,通过指令创建App,可创建多个app。
python manage.py startapp appname
(zero.demo.venv) PS E:\Zero.Apps\Python.Demo\ZeroDjangoDemo> python manage.py startapp serverapp
注意:在虚拟环境下安装Django的需要在虚拟环境下才能正常运行。
文件 | 说明 |
---|---|
migrations | 迁移文件 |
__init__.py | 包标识文件 |
admin.py | Django的后台文件 |
apps.py | 配置文件,配置单独添加的每个应用。 |
models.py | 数据库模型的文件 |
tests.py | 用来编写测试脚本的文件 |
views.py | 视图控制器文件 |
通过创建APP可以独立开功能,让每个模块单独管理对应的数据。
4.2 将APP添加到项目的settings.py文件中
需要将APP添加到INSTALLED_APPS列表中,直接添加app名称。
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'serverapp',
]
五、Django中的数据模型
5.1 ORM简介
对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。通过ORM可以将对不同数据库的操作转换成操作统一的ORM,可以大大提高开发效率,虽然执行效率会有所降低。
5.2 在App的models中创建模型
直接在models文件中创建类,类中的每个属性都与数据库中的字段一一对应。
class Person(models.Model):
"""Person model."""
name = models.CharField(max_length=10)
"""名称"""
phone = models.CharField(max_length=11)
'''Phone number'''
如果存在公用字段或者相同的字段,可以先创建一个公共字段的model,然后其他模型继承该公共模型。
使用内部类Meta,给模型赋予元数据。模型的元数据即“所有不是字段的东西”,比如排序选项( ordering ),数据库表名( db_table ),或是阅读友好的单复数名( verbose_name 和 verbose_name_plural )。这些都不是必须的,并且在模型当中添加 Meta类
也完全是可选的。
from django.db import models
# Create your models here.
class CreateUpdate(models.Model):
"""Create time and update time."""
create_at = models.DateTimeField(auto_now_add=True)
"""Create time"""
update_at = models.DateTimeField(auto_now = True)
"""Update time"""
# 给模型赋予元数据
class Meta:
abstract = True # 将model设置为抽象类,不会在数据库中创建表。
class Person(CreateUpdate):
"""Person model."""
name = models.CharField(max_length=10)
"""名称"""
phone = models.CharField(max_length=11)
'''Phone number'''
class Order(CreateUpdate):
"""Order model"""
order_id = models.CharField(max_length=20,db_index=True,primary_key=True)
"""Order id"""
order_desc = models.CharField(max_length=100)
"""Order desc"""
创建模型时需要指定每个字段的类型,创建数据库时才能对应的创建不同类型的字段。
常见models的类型官网连接:模型字段参考 | Django 文档 | Django (djangoproject.com)https://docs.djangoproject.com/zh-hans/4.2/ref/models/fields/#django.db.models.DateField
5.3 数据库迁移
5.3.1 配置数据库
Django的默认数据库为SQLite数据库,但是可以根据自己的需求修改数据库,本文以mysql为例修改数据库配置。
其他数据库连接连接配置参考官网链接:
数据库 | Django 文档 | Django (djangoproject.com)https://docs.djangoproject.com/zh-hans/4.2/ref/databases/
(1)修改settings中的DATABASES设置
将默认的数据库设置:
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
修改成mysql对应的设置:
DATABASES = {
'default': {
"ENGINE": "django.db.backends.mysql",
'NAME': 'djangodemo',
'USER': "root",
'PASSWORD': "数据库密码",
}
}
(2)在数据库中创建对应的表
我这边使用mysql自带的workbench客户端直接创建。
(3)安装数据库驱动,mysql使用pymysql驱动:
使用pip安装pymysql模块。
pip install pymysql
注意,若使用虚拟环境需要在虚拟环境下安装。
(zero.demo.venv) PS D:\Zero.App\Python.Demo> pip install pysql
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='pypi.org', port=443): Read timed out. (read timeout=15)")': /simple/pysql/
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='pypi.org', port=443): Read timed out. (read timeout=15)")': /simple/pysql/
WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='pypi.org', port=443): Read timed out. (read timeout=15)")': /simple/pysql/
Collecting pysql
Downloading pysql-0.16.tar.gz (127 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 127.4/127.4 kB 258.7 kB/s eta 0:00:00
Preparing metadata (setup.py) ... error
error: subprocess-exited-with-error
× python setup.py egg_info did not run successfully.
│ exit code: 1
╰─> [7 lines of output]
Traceback (most recent call last):
File "<string>", line 2, in <module>
File "<pip-setuptools-caller>", line 34, in <module>
File "C:\Users\LJM\AppData\Local\Temp\pip-install-q4vyk2w_\pysql_8e28709aa008466d87288d7dded139fd\setup.py", line 31
except Exception, e:
^
SyntaxError: invalid syntax
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed
× Encountered error while generating package metadata.
╰─> See above for output.
note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
(zero.demo.venv) PS D:\Zero.App\Python.Demo>
(4)修改APP的“__init__.py”文件,导入pymysql
import pymysql
pymysql.install_as_MySQLdb() # 加此句可以使pymysql发挥最大数据库操作性能。
5.3.2 执行数据迁移命令
python manage.py makemigrations # 生成迁移文件
python manage.py migrate # 迁移数据库,创建对应的表
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py makemigrations
It is impossible to add the field 'create_at' with 'auto_now_add=True' to person without providing a default. This is because the database needs something to populate existing rows.
1) Provide a one-off default now which will be set on all existing rows
2) Quit and manually define a default value in models.py.
Select an option: 1
Please enter the default value as valid Python.
Accept the default 'timezone.now' by pressing 'Enter' or provide another value.
The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as a value.
Type 'exit' to exit this prompt
[default: timezone.now] >>> timezone.now()
It is impossible to add a non-nullable field 'name' to person without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit and manually define a default value in models.py.
Select an option: 1
Please enter the default value as valid Python.
The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as a value.
Type 'exit' to exit this prompt
>>> admin
Invalid input: name 'admin' is not defined
>>> "admin"
It is impossible to add a non-nullable field 'phone' to person without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit and manually define a default value in models.py.
Please select a valid option: 1
Please enter the default value as valid Python.
The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as a value.
Type 'exit' to exit this prompt
>>> "12345678910"
Migrations for 'serverapp':
serverapp\migrations\0002_order_person_create_at_person_name_person_phone_and_more.py
- Create model Order
- Add field create_at to person
- Add field name to person
- Add field phone to person
- Add field update_at to person
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, serverapp, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying serverapp.0001_initial... OK
Applying serverapp.0002_order_person_create_at_person_name_person_phone_and_more... OK
Applying sessions.0001_initial... OK
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo>
此处遇到一些问题,非空字段需要有默认值,需要选择对用的选项然后数据一些默认值进行创建。
5.3.3 创建的数据表展示
创建表之后会自动创建一个主键id。
5.3.4 指定字段为主键
若要指定自己创建的字段为主键,只需要在models对应的字段中添加primary_key=True属性即可。
class Order(CreateUpdate):
"""Order model"""
order_id = models.CharField(max_length=20,db_index=True,primary_key=True)
"""Order id"""
order_desc = models.CharField(max_length=100)
"""Order desc"""
然后重新执行指令,一样要注意在对应的环境下执行。
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py makemigrations
Migrations for 'serverapp':
serverapp\migrations\0003_remove_order_id_alter_order_order_id.py
- Remove field id from order
- Alter field order_id on order
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, serverapp, sessions
Running migrations:
Applying serverapp.0003_remove_order_id_alter_order_order_id... OK
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo>
更新后,order_id就是我们设置的主键了(下图为sqlitestudio的界面视图)。
5.4 数据的基本操作API
演示直接在命令行中操作,需要在项目根目录下启用命令行,或者启动后切到项目目录下。
5.4.1 导入模块
(zero.demo.venv) PS D:\Zero.App\Python.Demo\ZeroDjangoDemo> python manage.py shell
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from serverapp.models import Person,Order
5.4.2 添加数据
# 方法1:直接使用create
>>> p = Person.objects.create(name = "xiaoming", phone = "123456")
# 方法2:先创建对象,然后调用save方法
>>> p = Person(name = "xiaoli", phone = "654321")
>>> p.save() # 必须调用保存方法才能保存数据。
5.4.3 查询数据
(1)单表查询
# 查找所有数据
>>> Person.objects.all()
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
# 查找单个数据
>>> Person.objects.get(name = "xiaoli")
<Person: Person object (2)>
# 查询指定条件的数据
# 字段名 + __exact 表示字段值必须为该数据
>>> Person.objects.filter(name__exact = "xiaoli")
<QuerySet [<Person: Person object (2)>]>
# 字段名 + __iexact 表示字段必须为设定值,且忽略大小写
>>> Person.objects.filter(name__iexact = "XIAOLI")
<QuerySet [<Person: Person object (2)>]>
# 字段名 + __gt 表示字段必须大于设定值
>>> Person.objects.filter(name__gt = 1)
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
# 字段名 + __lt 表示字段必须小于设定值
>>> Person.objects.filter(id__lt = 5)
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
# 字段名 + __contains 表示字段包含设置值,可通过order_by排序
>>> Person.objects.filter(name__contains = "xiao").order_by("id")
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
# 字段名 + __icontains 表示字段包含设置值,并忽略大小写
>>> Person.objects.filter(name__icontains = "a")
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
# 字段名 + __startswith 表示以...开始
>>> Person.objects.filter(name__startswith = "xiao")
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
# 字段名 + __istartswith 表示以...开始,并忽略大小写
>>> Person.objects.filter(name__istartswith = "XIAO")
<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>
# 字段名 + __endswith 表示以...结束
>>> Person.objects.filter(name__endswith = "li")
<QuerySet [<Person: Person object (2)>]>
# 字段名 + __iendswith 表示以...结束,并忽略大小写
>>> Person.objects.filter(name__iendswith = "Li")
<QuerySet [<Person: Person object (2)>]>
# 使用exclude方法可以排除满足条件的数据,与filter效果相反
>>> Person.objects.exclude(name = "xiaoli")
<QuerySet [<Person: Person object (1)>]>
(2)跨关系查询(多表联查)
使用双下划线“__”分割模型的小写名称,直到查询到自己要的字段。
先创建关联字段:
class Order(CreateUpdate):
"""Order model"""
order_id = models.CharField(max_length=20,db_index=True,primary_key=True)
"""Order id"""
order_desc = models.CharField(max_length=100)
"""Order desc"""
order_customer = models.ForeignKey(Person,related_name="Name",on_delete=models.CASCADE)
"""link to person"""
再搞几条数据:
以下是正向查找,使用Order表中的字段“order_customer”查找管理的persong的“name”字段
>>> Order.objects.filter(order_customer__name = "xiaoli")
<QuerySet [<Order: Order object (3)>, <Order: Order object (4)>]>
可以通过使用模型的小写名称激活反查,进行关系反差
>>> Person.objects.filter(order__order_id = 1)
<QuerySet [<Person: Person object (1)>]>
此处说一下:本人测试的时候刚开始出现了一个问题,就是进行发查的时候无法识别模块的小写名称,一直将模块名识别为字段名,报字段名称错误。一度重新迁移数据,重新进入django shell也是没有用,网上也没有搜到类似的问题。后面在多次尝试后,某一次推出shell,重新进入之后就可以了,而且也无法重新原来的问题。蛮记录下该问题。
错误信息如下:
>>> Person.objects.filter(order__order_id = 1)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\query.py", line 1436, in filter
return self._filter_or_exclude(False, args, kwargs)
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\query.py", line 1454, in _filter_or_exclude
clone._filter_or_exclude_inplace(negate, args, kwargs)
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\query.py", line 1461, in _filter_or_exclude_inplace
self._query.add_q(Q(*args, **kwargs))
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\sql\query.py", line 1534, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\sql\query.py", line 1565, in _add_q
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\sql\query.py", line 1415, in build_filter
lookups, parts, reffed_expression = self.solve_lookup_type(arg, summarize)
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\sql\query.py", line 1225, in solve_lookup_type
_, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\sql\query.py", line 1713, in names_to_path
raise FieldError(
django.core.exceptions.FieldError: Cannot resolve keyword 'order' into field. Choices are: Name, create_at, id, name, phone, update_at
>>> Order.objects.all()
<QuerySet [<Order: Order object (1)>, <Order: Order object (2)>, <Order: Order object (3)>, <Order: Order object (4)>]>
5.4.4 修改查询到的数据
先查询到具体数据,然后再进行修改:
>>> p = Person.objects.get(name = "xiaoli")
>>> print(p)
Person object (2)
>>> print(p.name + " " + p.phone)
xiaoli 654321
>>> p.name = "xiaoxiaoderener"
>>> p.save() # 需要调用save方法才会保存修改
>>> p = Person.objects.get(id = p.id)
>>> p.name
'xiaoxiaoderener'
或者可以使用get_or_create函数,如果不存在就直接创建。
# 注意,get_or_create返回的是元组,一个是数据对象,一个是布尔值
>>> p, is_created = Person.objects.get_or_create(name = "xiaoming")
>>> p.name
'xiaoming'
# 不存在时,直接创建一个数据
>>> p, is_created = Person.objects.get_or_create(name = "xiaolei")
>>> p.name
'xiaolei'
此时发现数据库中添加了原来并不存在的xiaolei,但是非空字段phone是空的,算是一个bug。
5.4.5 删除数据
返回的数据对象直接调用delete()方法,可以直接删除数据。
>>> p = Person.objects.get(id = 3)
>>> p.name
'xiaolei'
>>> p.delete()
(1, {'serverapp.Person': 1})
>>> p = Person.objects.get(id = 3)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "D:\Zero.App\Python.Demo\zero.demo.venv\lib\site-packages\django\db\models\query.py", line 637, in get
raise self.model.DoesNotExist(
serverapp.models.Person.DoesNotExist: Person matching query does not exist.
>>>
大多数情况下,已经创建的数据不建议删除,而是添加一个状态字段,isenabled或者status之类的,用false标记不可用状态。
六 管理后台
6.1 Django后台管理配置流程
-
定义管理类:在app的admin.py中定义一个类继承admin.ModelAdmin。
-
配置信息:在类中定义信息
-
绑定模型到创建的类中:将模型注册到admin中。
from django.contrib import admin
from serverapp.models import Person
# Register your models here.
class PersonAdmin(admin.ModelAdmin):
"""Admin class"""
list_display = ("name","phone") # 配置显示信息
admin.site.register(Person,PersonAdmin) # 将Person模型绑定到PersonAdmin类中
6.2 进入管理后台
先启动服务器:
python manage.py runserver
然后在浏览器输入网址和管理后台地址:
http://127.0.0.1:8000/admin
在显示的用户登陆界面输入账号和密码登陆:
即可进入后台管理页面,ServerApp就是我们自己的应用。
6.3 配置信息
6.3.1 配置后台显示语言
Django的默认后台显示语言是英文,可通过settings.py文件配置全局显示语言,修改后即可显示中文。
# 语言为中文
LANGUAGE_CODE = 'zh-Hans'
# 时区为亚洲上海
TIME_ZONE = 'Asia/Shanghai'
6.3.2 同时添加多个管理模块
(1)定义多个类,并且将类注册到django的admin中,可以通过后台管理多个模型。
class PersonAdmin(admin.ModelAdmin):
"""Admin class"""
list_display = ("name", "phone") # 配置显示信息
admin.site.register(Person, PersonAdmin) # 将Person模型绑定到PersonAdmin类中
class OrderAdmin(admin.ModelAdmin):
"""Admin class"""
list_display = ("order_id", "order_desc") # 配置显示信息
admin.site.register(Order, OrderAdmin) # 将Order模型绑定到OrderAdmin类中
(2)当不同模型拥有相同的字段时,可以对相同的字段进行设置,然后以列表的形式将不同的模型绑定到同一个类中。不同的模型在后台以相同的配置信息进行管理。
class PersonAdmin(admin.ModelAdmin):
"""Admin class"""
#list_display = ("name", "phone") # 配置显示信息
list_display = ("create_at", "update_at")
admin.site.register((Person,Order), PersonAdmin) # 将Person,Order模型绑定到PersonAdmin类中
6.3.3 常用配置信息介绍
(1)空值显示 empty_value_display
设置空值的显示内容,类中定义直接创建属性即可,输入的时候没有只能提示。
# 类中声明属性
class OederAdmin(admin.ModelAdmin):
empty_value_display = "(None)"
# 或者直接修改admin属性
admin.site.empty_value_display = "(None)" # 覆盖控制显示内容
(2)显示内容 list_display
以元组的形式设置显示的内容,元组的元素是模型中对应的字段。
class OrderAdmin(admin.ModelAdmin):
"""Admin class"""
list_display = ("order_id", "order_desc", "create_at") # 配置显示信息
(3) 数据过滤器 list_filter
以元组的形式添加过滤器,可以用于筛选数据。
class OrderAdmin(admin.ModelAdmin):
"""Admin class"""
list_display = ("order_id", "order_desc", "create_at") # 配置显示信息
list_filter = ("order_id", "create_at")
(4)搜索框 search_fields
以元组形式设置搜索字段,搜索使用的是模糊查找。
search_fields = ("order_id",) # 搜索框
(5)设置只读字段 readonly_fields
设置字段为只读属性。
readonly_fields = ("order_id", "create_at") # 设置只读字段
七 路由(urls)
7.1 路由处理流程
- 查找全局的urls.py文件
- 按照先后顺序逐一匹配
- 匹配到之后停止
- 没有匹配到,进行异常处理
7.2 路由表达式
7.2.1 精确字符串格式
使用精确字符串格式查找,具体到对应的地址信息,url需要一致才能匹配。
forder/name
7.2.2 转换格式
使用<类型:参数名>格式时表示字符串进行转换格式,将传入的数据转换成需要的数据。
# 要求传入数据为int型,然后参数对应的是param
forder/<int:param>
7.2.3 正则表达式
使用re_path(表达字符串进行匹配),根据正则表达式进行识别。
# 直接匹配
re_path(forder/("正则表达式"))
# 将匹配的数据传递给参数param
re_path(forder/(?P<param>"正则表达式"))
7.3 设置路由
7.3.1 找到全局路由配置文件 urls.py文件
Django默认已经创建一个路由组“admin/”,对应的是一组路由,然后再令行进行细分。
7.3.2 创建一个自己的路由组
创建也给路由组“serverapp/”,作为serverapp所有路由的人口,使用include函数指定路由文件为server app下的urls.py文件。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('serverapp/', include("serverapp.urls")), # 声明自己的路由组
]
7.3.3 在app下的urls中声明路由
在app的urls文件下声明路由,将路由指向对应的函数test
from django.urls import path,re_path
from serverapp import views as serverapp_views
urlpatterns = [
path('test/2023', serverapp_views.test), # 精确匹配
path('converter/<int:num>', serverapp_views.converter), # 格式转换
re_path(r'^re/(?P<num>[0-9]{1,4})/$', serverapp_views.rematch), # 正则表达式,通过添加起止符限制匹配,避免中间多级路径后匹配到,造成错误匹配。
]
views下的函数定义:
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def test(request):
"""method of test"""
return HttpResponse("Hello World.")
def converter(request, num):
"""method of converter"""
content = f"The number is : {num}"
return HttpResponse(content)
def rematch(request, num):
"""method of re match"""
content = f"The re match number is : {num}"
return HttpResponse(content)
7.3.4 路由示例
精确查找结果:
格式转换结果:
正则匹配结果: