版本: django 3.2.10 python 3.6
规范的项目结构
这里只列出了src 目录,我们着重来说一下它 。首先,其名称改为跟项目同名,下面 app : app1、app2、project, 其中project 是配置文件所在的 app
正常情况下, Django 会帮我们创建一 settings.py 录,所有 Django 的配置都在这个模块 中,这就产生一个问题:比如同份配置,怎么来更好区分开发环境 线上环境?
具体的做法是把之 settings.py 中的内容放到 settings/base. py ,删除 settings.py 文件, 同时新增init.py、develop.py、product.py 拆分独立模块之后 ,把需要独立配置的内容分放置在不同的模块中。
一 创建项目
打开命令行,cd 到一个你想放置你代码的目录,然后运行以下命令:
django-admin startproject mysite
- mysite是项目名
项目目录结构:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
- 最外层的 mysite/ 根目录只是你项目的容器, 根目录名称对 Django 没有影响,你可以将它重命名为任何你喜欢的名称。
- manage.py: 一个让你用各种方式管理 Django 项目的命令行工具。
- 里面一层的 mysite/ 目录包含你的项目,它是一个纯 Python 包。它的名字就是当你引用它内部任何东西时需要用到的 Python 包名。 (比如 mysite.urls).
- mysite/init.py:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包。
- mysite/settings.py:Django 项目的配置文件。
- mysite/urls.py:Django 项目的 URL 声明,就像你网站的“目录”。
- mysite/asgi.py:作为你的项目的运行在 ASGI 兼容的 Web 服务器上的入口。
- mysite/wsgi.py:作为你的项目的运行在 WSGI 兼容的Web服务器上的入口。
启动项目:
python manage.py runserver
用于开发的服务器在需要的情况下会对每一次的访问请求重新载入一遍 Python 代码。所以你不需要为了让修改的代码生效而频繁的重新启动服务器。然而,一些动作,比如添加新文件,将不会触发自动重新加载,这时你得自己手动重启服务器。
项目配置
# ALLOWED_HOSTS = [ ]
# *表示任何ip都能访问
ALLOWED_HOSTS = ['*']
修改站点语言
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-Hans'
# 修改站点时区
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
如果使用命名行创建的django项目,还需要配置模板路径:'DIRS': [os.path.join(BASE_DIR, 'templates')],
然后导入os模块;如果使用pycharm一键创建的django项目,只需在settings.py中导入os模块
TEMPLATES = [
{
...
# 原来 'DIRS': [],
# 修改
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
},
二 创建应用
在 Django 中,每一个应用都是一个 Python 包,并且遵循着相同的约定。Django 自带一个工具,可以帮你生成应用的基础目录结构,这样你就能专心写代码,而不是创建目录了。
项目 VS 应用
项目和应用有什么区别?
应用是一个专门做某件事的网络应用程序——比如博客系统,或者公共记录的数据库,或者小型的投票程序。
项目则是一个网站使用的配置和应用的集合。项目可以包含很多个应用。应用可以被很多个项目使用。
在这 manage.py 同级目录下创建投票应用。这样它就可以作为顶级模块导入,而不是 mysite 的子模块。请确定你现在处于 manage.py 所在的目录下,然后运行这行命令来创建一个应用:
python manage.py startapp polls
应用目录结构:
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
2.1 注册应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'polls.apps.PollsConfig', # 注册polls应用
]
三 创建模板
在开发中,创建模板的方式有两种,方法一:在每个APP下面各自创建自己的模板;方法二:就是统一放到项目同名的APP中(也就是项目目录写的templates文件夹下再创建应用名目录,里面放各自的模板)
后期如果配置多个模板,建议将模板文件放在项目目录下的文件夹里面
下面是使用方法一:
- 在你的 polls 目录里创建一个 templates 目录。Django 将会在这个目录里查找模板文件。
- 你项目的 TEMPLATES 配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了 DjangoTemplates 后端,并将 APP_DIRS 设置成了 True。这一选项将会让 DjangoTemplates 在每个 INSTALLED_APPS 文件夹中寻找 “templates” 子目录。
- 在你刚刚创建的 templates 目录里,再创建一个目录 polls,然后在其中新建一个文件 index.html 。换句话说,你的模板文件的路径应该是 polls/templates/polls/index.html 。因为
app_directories
模板加载器是通过上述描述的方法运行的,所以 Django 可以引用到 polls/index.html 这一模板了。
模板文件样例:polls/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<!-- <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> -->
<li><a href="{% url 'polls:detail' question_id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
</body>
</html>
注意:
模板命名空间
* 虽然我们现在可以将模板文件直接放在 polls/templates 文件夹中(而不是再建立一个 polls 子文件夹),但是这样做不太好。
* Django 将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django 没有办法 区分 它们。
* 我们需要帮助 Django 选择正确的模板,*最好的方法就是把他们放入各自的命名空间中*,也就是把这些模板放入一个和 自身 应用重名的子文件夹里。
- 有的教程会将应用模板,放在项目templates目录下(在项目目录下新建templates,然后再在templates目录下新建一个应用名目录,将应用的模板放在该目录下),结构如下:
mysite/
- manage.py
- mysite/
--...
- templates
-- polls
--- index.html
去除模板中的硬编码
在 polls/index.html 里编写投票链接时,链接是硬编码的:
问题在于,硬编码和强耦合的链接,对于一个包含很多应用的项目来说,修改起来是十分困难的。然而,因为你在 polls.urls 的 url() 函数中通过 name 参数为 URL 定义了名字,你可以使用 {% url %} 标签代替它:<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
这个标签的工作方式是在 polls.urls 模块的 URL 定义中寻具有指定名字的条目。你可以回忆一下,具有名字 ‘detail’ 的 URL 是在如下语句中定义的:<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
如果你想改变投票详情视图的 URL,比如想改成 polls/specifics/12/ ,你不用在模板里修改任何东西(包括其它模板),只要在 polls/urls.py 里稍微修改一下就行:...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
为 URL 名称添加命名空间
教程项目只有一个应用,polls 。在一个真实的 Django 项目中,可能会有五个,十个,二十个,甚至更多应用。Django 如何分辨重名的 URL 呢?举个例子,polls 应用有 detail 视图,可能另一个博客应用也有同名的视图。Django 如何知道 {% url %} 标签到底对应哪一个应用的 URL 呢?
答案是:在根 URLconf 中添加命名空间。在 polls/urls.py 文件中稍作修改,加上 app_name 设置命名空间:
polls/urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
]
现在,编辑 polls/index.html 文件,从:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
修改为指向具有命名空间的详细视图:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
四 创建视图函数
- 在Django中,视图是对web请求进行回应。视图就是一个python函数,在应用目录下views.py文件中定义
from django.shortcuts import render
def index(request):
return render(request, 'polls/index.html')
- 视图函数为
index()
- 视图函数的名称并不重要;不需要用一个统一的命名方式来命名,名称能够比较准确地反映出它实现的功能就行
- 快捷函数
render()
:载入模板,填充上下文,重写 index() 视图 - 上述代码的作用是:载入polls/index.html模板文件,返回HTML页面
类视图
后期如果视图函数比较多,需要使用类视图,创建方法:https://www.yuque.com/u1046159/lp12n4/czur1n#ZXGqF
五 配置url
5.1 方法一
如果一个项目下有很多的app就要根据不同的app来分类不同的url
在应用 polls 目录里新建一个 urls.py 文件。你的应用目录现在看起来应该是这样:
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
urls.py
views.py
在 polls/urls.py 中,输入如下代码:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
下一步是要在根 URLconf 文件中指定我们创建的 polls.urls 模块。在 mysite/urls.py 文件的 urlpatterns 列表里插入一个 include(), 如下:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
# ...
]
处理流程:
● 输入127.0.0.1:8000/polls/后
○ 程序先执行到项目的urls.py文件,寻找是否有被包含的应用文件 --> path('polls/', include('polls.urls'))
○ 程序接着转至应用polls的urls.py文件,尝试查找对应的视图函数 -->path('', views.index, name='index'),
○ 程序最后调用views.py下定义好的视图函数然后返回结果 -->def index(request):
何时使用 include()
当包括其它 URL 模式时你应该总是使用 include() , admin.site.urls 是唯一例外。
5.2 方法二
此方法对于应用数量比较少时方便
先在项目polls的urls.py中,先导入应用视图(from polls import views
),然后在path()中使用views.index()
polls/urls.py
from django.contrib import admin
from django.urls import path
from polls import views
urlpatterns = [
# ...
path('polls/',views.index)
]
再在应用的views.py中编写视图函数
from django.shortcuts import render
# Create your views here.
def index(request):
return render(request, 'polls/index.html')
处理流程:
浏览器访问localhost:8080/polls时
● 程序先执行到项目的urls.py文件,寻找是否有被包含的应用文件,发现有,将URL的处理交给应用的视图函数index()
● 程序最后调用应用polls的views.py下定义好的视图函数然后返回结果。
● 应用视图函数返回的是index.html页面
5.3 url注意事项
六 创建模型类
编辑 polls/models.py 文件
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
class Meta:
# 增加ordering,否则分页查询时出现warning
# ordering = ['id']
# 定义表名
db_table = 'question'
# 定义在管理后台显示的名称
verbose_name = '问题'
给模型增加 str() 方法是很重要的,这不仅仅能给你在命令行里使用带来方便,Django 自动生成的 admin 里也使用这个方法来表示对象。
6.1 激活模型
上面的一小段用于创建模型的代码给了 Django 很多信息,通过这些信息,Django 可以:
- 为这个应用创建数据库 schema(生成 CREATE TABLE 语句)。
- 创建可以与 Question 和 Choice 对象进行交互的 Python 数据库 API。
但是首先得把 polls 应用安装到我们的项目里。
为了在我们的工程中包含这个应用,我们需要在配置类 INSTALLED_APPS 中添加设置。因为 PollsConfig 类写在文件 polls/apps.py 中,所以它的点式路径是 ‘polls.apps.PollsConfig’。在文件 mysite/settings.py 中 INSTALLED_APPS 子项添加点式路径后,它看起来像这样:
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
也可以直接写上应用名,如下:
INSTALLED_APPS = [
'polls',
# ...
]
这是因为polls/apps.py中定义了PollsConfig类的名字
现在你的 Django 项目会包含 polls 应用。接着运行下面的命令:
python manage.py makemigrations polls
现在,再次运行 migrate 命令,在数据库里创建新定义的模型的数据表(数据库中表名默认名为应用名_模型类名小写
:polls_questions):
python manage.py migrate
6.2 改变模型(数据库迁移)
改变模型需要这三步:
- 编辑 models.py 文件,改变模型。
- 将当前应用注册到setting里面
运行 python manage.py makemigrations 为模型的改变生成迁移文件。
python manage.py makemigrations
运行 python manage.py migrate 来应用数据库迁移。
python manage.py migrate
七 静态文件
首先,在你的 polls 目录下创建一个名为 static 的目录。Django 将在该目录下查找静态文件,这种方式和 Diango 在 polls/templates/ 目录下查找 template 的方式类似。
在你刚创建的 static 文件夹中创建一个名为 polls 的文件夹,再在 polls 文件夹中创建一个名为 style.css 的文件。换句话说,你的样式表路径应是 polls/static/polls/style.css。因为 AppDirectoriesFinder 的存在,你可以在 Django 中以 polls/style.css 的形式引用此文件,类似你引用模板路径的方式。
静态文件命名空间
虽然我们可以像管理模板文件一样,把 static 文件直接放入 polls/static (而不是创建另一个名为 polls 的子文件夹),不过这实际上是一个很蠢的做法。Django 只会使用第一个找到的静态文件。如果你在 其它 应用中有一个相同名字的静态文件,Django 将无法区分它们。我们需要指引 Django 选择正确的静态文件,而最好的方式就是把它们放入各自的 命名空间 。也就是把这些静态文件放入 另一个 与应用名相同的目录中。
下一步,在 polls/templates/polls/index.html 的文件头添加以下内容:
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">
{% static %} 模板标签会生成静态文件的绝对路径。
这就是你开发所需要做的所有事情了。
启动服务器(如果它正在运行中,重新启动一次)
问题
如果加载静态文件报错,在settings.py中加入:
STATIC_URL = '/static/'
#添加这段代码
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
还有注意静态文件写法:
<link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.css' %}"/>
<script type="text/javascript" src="{% static 'js/echarts.js' %}"/>
正确:{% static 'css/bootstrap.css' %}
错误:{ % static 'css/bootstrap.css' % }
,%与{ }之间不能有空格,pycharm写的时候会加空格
八 配置MySQL数据库
下载pymysql
pip install pymysql
在settings.py修改DATABASES选项
修改前:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
修改后:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'graduation', #数据库名称
'USER': 'root',
'PASSWORD': '123456',
'HOST': 'localhost',
'PORT': '3306',
}
}
- 在项目名下的_init.py_中加入以下代码
import pymysql
pymysql.install_as_MySQLdb()
九 模板继承
9.1 用法
父模板base.html中使用block标签:
{% block head %}
<h1>父模板</h1>
{% endblock %}
- 其中head是block标签的名字
- 每个block标签不能同名
重写父模板中内容
{% extends 'base.html' %}
# 使用一:重写父模板中内容
{% block head %}
<h1>子模板</h1>
{% endblock %}
- 模板中使用了 “{% extends %}“ ,那么它必须是这个模板中的第一个模板 tag ,否则它就不工作
父模板内容扩展(block.super)
所谓父模板内容扩展,即对父模板中的 block 包含内容进行添加,而并非替换。Django 为实现这一功能需求提供了 {{ block.super }} 变量,可以获取到父模板中渲染后的结果并对父模板内容进行添加
{% extends 'base.html' %}
{% block content %}
{{block.super}}
<h1>子模板</h1>
{% endblock %}
9.2 项目中遇到的问题
下面是项目结构:
FCM_PROD_V1
- FCM_PROD //项目目录
-- ...
- spare_parts //应用
-- ...
-- templates //应用的模板目录
--- spare_parts
---- index.html
- templates // 存放项目共用模板
-- base.html
现在想在应用spare_parts的index.html中继承项目目录templates下的base.html里面内容(之所以这样设计,是想让公共部分抽离出来)
base.html
<!DOCTYPE html>
<html lang="en">
{% load static %}
{% block head %}
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap-theme.css' %}" />
<script type="text/javascript" src="{% static 'js/echarts.js' %}"></script>
<script type="text/javascript" src="{% static 'js/echarts.min.js' %}"></script>
</head>
{% endblock %}
</html>
index.py
{% extends 'base.html' %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
注意:子模板中引用父模板路径写法:{% extends 'base.html' %}
之所以django能找到,是因为settings.py里面设置,django会从templates文件夹自动寻找模板
十 在 admin 后台注册模型
使用以下命令创建超级管理员用户
python manage.py createsuperuser
要在后台注册我们自己创建的几个模型,这样 django admin 才能知道它们的存在,注册非常简单,只需要在应用目录polls\admin.py 中加入下面的代码:
from .models import Question
admin.site.register(Question)
这时访问 http://127.0.0.1:8000/admin/ 可以看见我们刚注册的模型