好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Django入门(一)

跟书《python编程:从入门到实践》,学习用Django编写名为“学习笔记”的Web应用程序。

建立项目

项目路径:learning_log

安装python3.7:

此处省略,参考这里:https://blog.csdn.net/miss1181248983/article/details/90779786

建立虚拟环境:
#?cd?/opt/#?mkdir?learning_log?&&?cd?learning_log#?python?-m?venv?11_env

激活虚拟环境:
#?source?ll_env/bin/activate

进入虚拟环境终端。

要停止使用虚拟环境,可执行:

#?deactivate

安装Django:
#?pip3?install?Django

Django仅在虚拟环境处于活动状态时才可用。

下面与书中不同部分是由于Django版本更新导致,照着操作即可。本人Django版本为2.2.3,可通过命令 python -m django --version 查看Django版本。

在Django中创建项目:
#?django-admin.py?startproject?learning_log?.#?lslearning_log??ll_env??manage.py#?ls?learning_log/__init__.py??settings.py??urls.py??wsgi.py

Django新建了一个名为 learning_log 的目录。它还创建了一个名为 manage.py 的文件,这是一个简单的程序,它接受命令并将其交给Django的相关部分去运行。

目录 learning_log 包含4个文件,其中最重要的是 settings.py 、 urls.py 和 wsgi.py 。

文件settings.py指定Django如何与你的系统交互以及如何管理项目。 文件urls.py告诉Django应创建哪些网页来响应浏览器请求。 文件wsgi.py帮助Django提供它创建的文件,这个文件名是web server gateway interface(Web服务器网关接口)的首字母缩写。

创建数据库:
#?python?manage.py?migrate

报错:

django.core.exceptions.ImproperlyConfigured:?SQLite?3.8.3?or?later?is?required?(found?3.7.17).

查看系统的sqlite3版本:

#?sqlite3?--version3.7.17?2013-05-20?00:56:22?118a3b35693b134d56ebd780123b7fd6f1497668

系统自带的sqlite3版本比较低,需要更新版本。

更新sqlite3版本:
#下载安装#?cd?/software#?wget?https://HdhCmsTestsqlite.org/2019/sqlite-autoconf-3270200.tar.gz#?tar?-zxf?sqlite-autoconf-3270200.tar.gz#?cd?sqlite-autoconf-3270200#?./configure?--prefix=/usr/local/#?make?&&?make?install

#更换版本#?find?/usr?-name?sqlite3/usr/bin/sqlite3
/usr/lib64/python2.7/sqlite3
/usr/local/bin/sqlite3
/usr/python/lib/python3.7/sqlite3#?/usr/local/bin/sqlite3?--version3.27.2?2019-02-25?16:06:06?bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7#?mv?/usr/bin/sqlite3?/usr/bin/sqlite3.bak#?ln?-s?/usr/local/bin/sqlite3?/usr/bin/sqlite3#?sqlite3?--version3.27.2?2019-02-25?16:06:06?bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7

#路径传递给共享库#?echo?'export?LD_LIBRARY_PATH="/usr/local/lib"'?>>?~/.bashrc#?source?!$#?cd?/opt/learning_log/#?rm?-rf?/software/sqlite-autoconf-3270200*

继续创建数据库:
#?python?manage.py?migrate#?lsdb.sqlite3??learning_log??ll_env??manage.py

查看项目:

对于虚拟机环境,建议指定本机IP和端口,否则默认是 127.0.0.1:8000 ,浏览器会无法访问。

#?python?manage.py?runserver?192.168.30.128:8000#?vim?learning_log/settings.pyALLOWED_HOSTS?=?['192.168.30.128']??????????????#允许主机中,添加本机IP或*(任意主机)

Django启动一个服务器,让你能够查看系统中的项目,了解它们的工作情况。当你在浏览器中输入URL以请求网页时,该Django服务器将进行响应:生成合适的网页,并将其发送给浏览器。

打开浏览器,输入 192.168.30.128:8000 访问Django项目,如下图:

创建应用程序

应用路径:learning_logs

Django项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。我们暂时只创建一个应用程序,它将完成项目的大部分工作。

激活虚拟环境

虚拟机再打开一个终端

#?cd?/opt/learning_log/#?source?ll_env/bin/activate

#?python?manage.py?startapp?learning_logs#?lsdb.sqlite3??learning_log??learning_logs??ll_env??manage.py#?ls?learning_logs/admin.py??apps.py??__init__.py??migrations??models.py??tests.py??views.py

上面新增了 learning_logs 目录,其中 models.py 用来定义我们要在应用程序中管理的数据。

定义模型
#?vim?learning_logs/models.py

from?django.db?import?modelsclass?Topic(models.Model):
????"""用户学习的主题"""
????text?=?models.CharField(max_length=200)
????date_added?=?models.DateTimeField(auto_now_add=True)

????def?__str__(self):
????????"""返回模型的字符串表示"""
????????return?self.text

创建了一个名为Topic的类,它继承了Model——Django中一个定义了模型基本功能的类。Topic类只有两个属性: text 和 date_added 。

属性 text 是一个CharField——由字符或文本组成的数据,需要存储少量的文本,如名称、标题或城市时,可使用CharField。定义CharField属性时,需要告诉Django该在数据库中预留多少空间,这里设置为200个字符。

属性 date_added 是一个DateTimeField——记录日期和时间的数据。传递了实参 auto_add_now=True ,每当用户创建新主题时,这都让Django将这个属性自动设置成当前日期和时间。

激活模型

要使用模型,必须让Django将应用程序包含到项目中。

#?vim?learning_log/settings.pyINSTALLED_APPS?=?[
????'django.contrib.admin',????'django.contrib.auth',????'django.contrib.contenttypes',????'django.contrib.sessions',????'django.contrib.messages',????'django.contrib.staticfiles',????#?我的应用程序
????'learning_logs',????????????????#增加该行]

还需要让Django修改数据库,使其能够存储于模型Topic相关的信息。

#?python?manage.py?makemigrations?learning_logs#?python?manage.py?migrate

在这里,Django确认为learning_logs 应用迁移时一切OK。

每当需要修改项目管理的数据时,都采取如下三个步骤:

修改 models.py ; 对 learning_logs 调用 makemigrations ; 让Django迁移项目。 Django管理网站 创建超级用户:Django允许创建具备所有权限的用户——超级用户。
#?python?manage.py?createsuperuserUsername?(leave?blank?to?use?'root'):?ll_admin??????????????#自定义用户名Email?address:??????????????#可为空Password:???????????????#自定义密码,不小于8位Password?(again):?
Superuser?created?successfully.

向管理网站注册模型:非自动创建的模型需要手工注册。
#?vim?learning_logs/admin.py

from?django.contrib?import?adminfrom?learning_logs.models?import?Topic

admin.site.register(Topic)

导入我们要注册的模型Topic,让Django通过管理网站管理我们的模型。使用超级用户访问管理网站: 192.168.30.128:8000/admin/ 。

添加主题:注册Topic后,添加主题Chess和Rock Climbing。

定义模型Entry

要记录学到的Chess和Rock Climbing知识,需要为用户可在“学习笔记”中添加的条目定义模型。每个条目都与特定主题相关联,这种关系被称为多对一关系,即多个条目可关联到同一个主题。

#?vim?learning_logs/models.py

from?django.db?import?modelsclass?Topic(models.Model):
????"""用户学习的主题"""
????text?=?models.CharField(max_length=200)
????date_added?=?models.DateTimeField(auto_now_add=True)

????def?__str__(self):
????????"""返回模型的字符串表示"""
????????return?self.textclass?Entry(models.Model):
????"""学到的有关某个主题的具体知识"""
????topic?=?models.ForeignKey(Topic)
????text?=?models.TextField()
????date_added?=?models.DateTimeField(auto_now_add=True)
????
????class?Meta:
????????verbose_name_plural?=?'entries'

????def?__str__(self):
????????"""返回模型的字符串表示"""
????????return?self.text[:50]?+?"..."

像Topic一样,Entry也继承了Django基类Model。属性 topic 是一个ForeignKey实例,外键引用了数据库中的另一条记录,这些代码将每个条目关联到特定的主题。每个主题创建时,都给它分配了一个键(ID),在两项数据之间需要建立联系时,Django使用与每项信息相关联的键。

属性 text 是一个TextField实例,这个字段不需要限制长度。属性 date_added 能够按创建顺序呈现条目,且在每个条目旁边放置时间戳。

在Entry类中嵌套Meta类,Meta类存储用于管理模型的额外信息,使用一个特殊属性让Django在需要时使用Entries来表示多个条目;如果没有这个类,Django将使用Entrys来表示多个条目。方法 __str__() 告诉Django在呈现条目时应显示text的前50个字符,超出则用 ... 显示。

迁移模型Entry
#?python?manage.py?makemigrations?learning_logs

报错:

TypeError:?__init__()?missing?1?required?positional?argument:?'on_delete'

解决——修改models.py:

from?django.db?import?modelsclass?Topic(models.Model):
????"""用户学习的主题"""
????text?=?models.CharField(max_length=200)
????date_added?=?models.DateTimeField(auto_now_add=True)

????def?__str__(self):
????????"""返回模型的字符串表示"""
????????return?self.textclass?Entry(models.Model):
????"""学到的有关某个主题的具体知识"""
????topic?=?models.ForeignKey(Topic,?on_delete=models.CASCADE)
????text?=?models.TextField()
????date_added?=?models.DateTimeField(auto_now_add=True)

????class?Meta:
????????verbose_name_plural?=?'entries'

????def?__str__(self):
????????"""返回模型的字符串表示"""
????????return?self.text[:50]?+?"..."

models.CASCADE 这个参数在老版本中是默认值。 on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值: CASCADE:此值设置,是级联删除; PROTECT:此值设置,是会报完整性错误; SET_NULL:此值设置,会把外键设置为null,前提是允许为null; SET_DEFAULT:此值设置,会把设置为外键的默认值; SET():此值设置,会调用外面的值,可以是一个函数。

再次迁移模型Entry:

#?python?manage.py?makemigrations?learning_logs#?python?manage.py?migrate

向管理网站注册模型Entry
#?vim?learning_logs/admin.py

from?django.contrib?import?adminfrom?learning_logs.models?import?Topic,?Entry

admin.site.register(Topic)admin.site.register(Entry)

查看网页,添加条目

下拉选择对应的Topic,Text添加任意内容

继续添加主题Chess的条目,然后再添加主题Rock Climbing的条目

使用Django shell

Django shell用于测试项目及排除项目故障,要退出shell会话,可按Ctr + D。

#?python?manage.py?shell>>>?from?learning_logs.models?import?Topic>>>?Topic.objects.all()<QuerySet?[<Topic:?Chess>,?<Topic:?Rock?Climbing>]>

在活动的虚拟环境中执行时,命令 python manage.py shell 启动一个Python解释器,可使用它来探索存储在项目数据库中的数据。

在这里,我们导入了模块 learning_logs.models 中的模型Topic,然后使用方法 Topic.objects.all() 来获取模型Topic的所有实例;它返回的是一个列表,称为查询集(queryset)。

查看分配给每个主题对象的ID:
>>>?topics?=?Topic.objects.all()>>>?for?topic?in?topics:...?????print(topic.id,?topic)...?
1?Chess
2?Rock?Climbing

可以看到,主题Chess的ID为1,而Rock Climbing的ID为2。

获取任意属性的值:

知道对象的ID后,就可以获取该对象并查看其任何属性。

>>>?t?=?Topic.objects.get(id=1)>>>?t.text'Chess'>>>?t.date_added
datetime.datetime(2019,?7,?9,?2,?5,?18,?289746,?tzinfo=<UTC>)

查看与主题相关联的条目:
>>>?t.entry_set.all()<QuerySet?[<Entry:?The?opening?is?thefirst?part?ofthe?game,?roughly?t...>,?<Entry:?In?the?opening?phase?ofthe?game,?it's?important?to...>]>>>>?t2?=?Topic.objects.get(id=2)>>>?t2.entry_set.all()<QuerySet?[<Entry:?One?ofthe?most?importantconcepts?in?climbing?is?to...>]>

创建主页网页

使用Django创建网页的过程通常分三个阶段:定义URL、编写视图和编写模板。

首先,你必须定义URL模式。URL模式描述了URL是如何设计的,让Django知道如何将浏览器请求与网站URL匹配,以确定返回哪个网页。每个URL都被映射到特定的视图——视图函数获取并处理网页所需的数据。视图函数通常调用一个模板,后者生成浏览器能够理解的网页。

映射URL

用户通过在浏览器中输入URL以及单击链接来请求网页,因此我们需要确定项目需要哪些URL。主页的URL最重要,它是用户用来访问项目的基础URL。

#?vim?learning_log/urls.py

from?django.contrib?import?adminfrom?django.urls?import?path,?include

urlpatterns?=?[
????path('admin/',?admin.site.urls),
????path('',?include('learning_logs.urls',?namespace='learning_logs')),]

这里保存完文件之后会报 ModuleNotFoundError: No module named 'learning_logs.urls' 错误,不用理会,继续往下做。

在文件夹learning_logs中创建另一个urls.py文件

#?vim?learning_logs/urls.py

"""定义learning_logs的URL模式"""from?django.urls?import?pathfrom?.?import?views

app_name='learning_logs'urlpatterns?=?[
????#?主页
????path('',?views.index,?name='index'),]

编写视图

视图函数接受请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器——这通常是使用定义了网页是什么样的模板实现的。

#?vim?learning_logs/views.py

from?django.shortcuts?import?renderfrom?.models?import?Topicdef?index(request):
????"""学习笔记的主页"""
????return?render(request,?'learning_logs/index.html')

导入了函数 render() ,它根据视图提供的数据渲染响应。URL请求与刚才定义的模式匹配时,Django将在文件views.py中查找函数 index() ,再将请求对象传递给这个视图函数。

编写模板:

模板定义了网页的结构。模板指定了网页是什么样的,而每当网页被请求时,Django将填入相关的数据。模板让你能够访问视图提供的任何数据。

#?mkdir?-p?learning_logs/templates/learning_logs#?vim?learning_logs/templates/learning_logs/index.html

<p>Learning?Logp><p>Learning?Log?helps?you?keep?track?of?your?learning,?for?any?topic?you're?learning?about.p>

标签

标识段落;标签

指出了段落的开头位置,而标签

指出了段落的结束位置。 访问网页:

访问基础URL—— 192.168.30.128:8000 ,可以看到刚刚定义的模板index.html。

创建其它网页

在创建完主页之后,继续创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,我们都将指定URL模式,编写一个视图函数,并编写一个模板。

模板继承

创建网站时,几乎都有一些所有网页都将包含的元素。在这种情况下,可编写一个包含通用元素的父模板,并让每个网页都继承这个模板。

父模板:首先来创建一个名为base.html的模板,并将其存储在index.html所在的目录中。这个文件包含所有页面都有的元素;其他的模板都继承base.html。
#?vim?learning_logs/templates/learning_logs/base.html

<p>
??<a?href="{%?url?'learning_logs:index'?%}">Learning?Loga>p>{%?block?content?%}{%?endblock?content?%}

第一部分创建一个包含项目名的段落,该段落也是一个到主页的链接,为创建链接,我们使用了一个模板标签。模板标签 {% url 'learning_logs:index' %} 生成一个URL,该URL与 learning_logs/urls.py 中定义的名为index的URL模式匹配。

第二部分插入了一对块标签。这个块名为content,是一个占位符,其中包含的信息将由子模板指定。

子模板:现在要重新编写index.html,使其继承base.html。
#?vim?learning_logs/templates/learning_logs/index.html

{%?extends?"learning_logs/base.html"?%}

{%?block?content?%}??<p>Learning?Log?helps?you?keep?track?of?your?learning,?for?any?topic?you're?learning?about.p>{%?endblock?content?%}

子模板的第一行必须包含标签 {% extends %} ,让Django知道它继承了哪个父模板。

然后插入了一个名为content 的 {% block %} 标签,以定义content块,不是从父模板继承的内容都包含在content块中。

显示所有主题 URL模式:

定义显示所有主题的页面的URL。

#?vim?learning_logs/urls.py

"""定义learning_logs的URL模式"""from?django.urls?import?pathfrom?.?import?views

app_name='learning_logs'urlpatterns?=?[
????#?主页
????path('',?views.index,?name='index'),

????#?显示所有的主题
????path('topics/',?views.topics,?name='topics'),]

只在用于主页URL的正则表达式中添加了 topics/ ,Django检查请求的URL时,这个模式与这样的URL匹配:基础URL后面跟着topics。其URL与该模式匹配的请求都将交给views.py中的函数 topics() 进行处理。

修改视图:

函数 topics() 需要从数据库中获取一些数据,并将其发送给模板。

#?vim?learning_logs/views.py

from?django.shortcuts?import?renderfrom?.models?import?Topicdef?index(request):
????"""学习笔记的主页"""
????return?render(request,?'learning_logs/index.html')def?topics(request):
????"""显示所有主题"""
????topics?=?Topic.objects.order_by('date_added')
????context?=?{'topics':?topics}
????return?render(request,?'learning_logs/topics.html',?context)

函数topics() 包含一个形参:Django从服务器那里收到的request对象。然后查询数据库——请求提供Topic对象,并按属性 date_added 对它们进行排序。我们将返回的查询集存储在topics中。

接着定义了一个将要发送给模板的上下文。上下文是一个字典,其中的键是我们将在模板中用来访问数据的名称,而值是我们要发送给模板的数据。在这里,只有一个键—值对,它包含我们将在网页中显示的一组主题。创建使用数据的网页时,除对象request和模板的路径外,我们还将变量context传递给 render() 。

编写模板:

显示所有主题的页面的模板接受字典context,以便能够使用 topics() 提供的数据。

#?vim?learning_logs/templates/learning_logs/topics.html

{%?extends?"learning_logs/base.html"?%}

{%?block?content?%}??<p>Topicsp>
??
??<ul>
????{%?for?topic?in?topics?%}??????<li>{{?topic?}}li>
????{%?empty?%}??????<li>No?topics?have?been?added?yet.li>
????{%?endfor?%}??ul>
??{%?endblock?content?%}

首先使用标签 {% extends %} 来继承base.html,接着开始定义content块。在标准HTML中,项目列表被称为无序列表,用标签

表示。

然后使用一个相当于for循环的模板标签,它遍历字典context中的列表topics。在模板中,每个for循环都必须使用 {% endfor %} 标签来显式地指出其结束位置。

在循环中,要将每个主题转换为一个项目列表项。要在模板中打印变量,需要将变量名用双花括号括起来。HTML标签

表示一个项目列表项,在标签对 内部,位于标签 和之间的内容都是一个项目列表项。

修改父模板,使其包含到显示所有主题的页面的链接:

#?vim?learning_logs/templates/learning_logs/base.html

<p>
??<a?href="{%?url?'learning_logs:index'?%}">Learning?Loga>?-??<a?href="{%?url?'learning_logs:topics'?%}">Topicsa>p>{%?block?content?%}{%?endblock?content?%}

在到主页的链接后面添加了一个连字符 - ,然后添加了一个到显示所有主题的页面的链接,使用的也是模板标签url。

访问网页:

访问基础URL—— 192.168.30.128:8000 ,可以看到定义的模板index.html及Topics链接。

点击Topics链接,查看主题

显示特定主题页面

接下来,重复之前步骤,创建一个专注于特定主题的页面——显示该主题的名称及该主题的所有条目。同样的,我们将定义一个新的URL模式,编写一个视图并创建一个模板。

URL模式:

显示特定主题的页面的URL模式与前面的所有URL模式都稍有不同,因为它将使用主题的id属性来指出请求的是哪个主题。

#?vim?learning_logs/urls.py

"""定义learning_logs的URL模式"""from?django.urls?import?path,?re_pathfrom?.?import?views

app_name='learning_logs'urlpatterns?=?[
????#?主页
????path('',?views.index,?name='index'),

????#?显示所有的主题
????path('topics/',?views.topics,?name='topics'),

????#?特定主题的详细页面
????re_path(r'^topics/(?P\d+)/$',?views.topic,?name='topic'),]

这里用到了python正则表达式, /(?P 与包含在两个斜杠内的整数匹配,并将这个整数存储在一个名为 topic_id 的实参中。 ?P 将匹配的值存储到 topic_id 中;而表达式 \d+ 与包含在两个斜杆内的任何数字都匹配,不管这个数字为多少位。

发现URL与这个模式匹配时,Django将调用视图函数 topic() ,并将存储在 topic_id 中的值作为实参传递给它。

修改视图:
#?vim?learning_logs/views.py

from?django.shortcuts?import?renderfrom?.models?import?Topicdef?index(request):
????"""学习笔记的主页"""
????return?render(request,?'learning_logs/index.html')def?topics(request):
????"""显示所有主题"""
????topics?=?Topic.objects.order_by('date_added')
????context?=?{'topics':?topics}
????return?render(request,?'learning_logs/topics.html',?context)def?topic(request,?topic_id):
????"""显示一个主题及其详细页面"""
????topic?=?Topic.objects.get(id=topic_id)
????entries?=?topic.entry_set.order_by('-date_added')
????context?=?{'topic':?topic,?'entries':?entries}
????return?render(request,?'learning_logs/topic.html',?context)

第一个除request对象外还包含另一个形参的视图函数。这个函数接受正则表达式 (?P 捕获的值,并将其存储到 topic_id 中。

使用 get() 来获取指定的主题,获取与该主题相关联的条目,并将它们按 date_added 排序: date_added 前面的减号指定按降序排列,即先显示最近的条目。将主题和条目都存储在字典context中,再将这个字典发送给模板topic.html。

编写模板:
#?vim?learning_logs/templates/learning_logs/topic.html

{%?extends?'learning_logs/base.html'?%}

{%?block?content?%}??<p>Topic:?{{?topic?}}p>

??<p>Entries:p>
??<ul>
??{%?for?entry?in?entries?%}????<li>
??????<p>{{?entry.date_added|date:'M?d,?Y?H:i'?}}p>
??????<p>{{?entry.text|linebreaks?}}p>
????li>
??{%?empty?%}????<li>
??????There?are?no?entries?for?this?topic?yet.????li>
??{%?endfor?%}??ul>{%?endblock?content?%}

修改topics模板:

将显示示所有主题的页面中的每个主题都设置为链接

#?vim?learning_logs/templates/learning_logs/topics.html

{%?extends?"learning_logs/base.html"?%}

{%?block?content?%}??<p>Topicsp>

??<ul>
????{%?for?topic?in?topics?%}??????<li>
????????<a?href="{%?url?'learning_logs:topic'?topic.id?%}">{{?topic?}}a>
	??li>
????{%?empty?%}??????<li>No?topics?have?been?added?yet.li>
????{%?endfor?%}??ul>{%?endblock?content?%}

使用模板标签url 根据learning_logs中名为topic的URL模式来生成合适的链接。这个URL模式要求提供实参 topic_id ,因此在模板标签url中添加了属性 topic.id 。

访问网页:

查看更多关于Django入门(一)的详细内容...

  阅读:30次

上一篇: Django入门(二)

下一篇:汉诺塔问题函数