Django入门(一) 我不是女神ヾ 2021-12-12 13:23 393阅读 0赞 > 跟书《python编程:从入门到实践》,学习用Django编写名为“学习笔记”的Web应用程序。 ### 建立项目 ### > 项目路径:learning\_log * 安装python3.7: 此处省略,参考这里:[https://blog.csdn.net/miss1181248983/article/details/90779786][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 . # ls learning_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 --version 3.7.17 2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668 系统自带的sqlite3版本比较低,需要更新版本。 * 更新sqlite3版本: #下载安装 # cd /software # wget https://www.sqlite.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 --version 3.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 --version 3.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 # ls db.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.py ALLOWED_HOSTS = ['192.168.30.128'] #允许主机中,添加本机IP或*(任意主机) Django启动一个服务器,让你能够查看系统中的项目,了解它们的工作情况。当你在浏览器中输入URL以请求网页时,该Django服务器将进行响应:生成合适的网页,并将其发送给浏览器。 打开浏览器,输入`192.168.30.128:8000`访问Django项目,如下图: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70] -------------------- ### 创建应用程序 ### > 应用路径:learning\_logs Django项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。我们暂时只创建一个应用程序,它将完成项目的大部分工作。 -------------------- #### 激活虚拟环境 #### 虚拟机再打开一个终端 # cd /opt/learning_log/ # source ll_env/bin/activate # python manage.py startapp learning_logs # ls db.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 models class 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.py INSTALLED_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。 每当需要修改项目管理的数据时,都采取如下三个步骤: 1. 修改`models.py`; 2. 对`learning_logs`调用`makemigrations`; 3. 让Django迁移项目。 -------------------- #### Django管理网站 #### * 创建超级用户:Django允许创建具备所有权限的用户——超级用户。 # python manage.py createsuperuser Username (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 admin from learning_logs.models import Topic admin.site.register(Topic) 导入我们要注册的模型Topic,让Django通过管理网站管理我们的模型。使用超级用户访问管理网站:`192.168.30.128:8000/admin/`。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 1] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 2] * 添加主题:注册Topic后,添加主题Chess和Rock Climbing。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 3] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 4] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 5] -------------------- #### 定义模型Entry #### 要记录学到的Chess和Rock Climbing知识,需要为用户可在“学习笔记”中添加的条目定义模型。每个条目都与特定主题相关联,这种关系被称为多对一关系,即多个条目可关联到同一个主题。 # vim learning_logs/models.py from django.db import models class Topic(models.Model): """用户学习的主题""" text = models.CharField(max_length=200) date_added = models.DateTimeField(auto_now_add=True) def __str__(self): """返回模型的字符串表示""" return self.text class 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][models.py]: from django.db import models class Topic(models.Model): """用户学习的主题""" text = models.CharField(max_length=200) date_added = models.DateTimeField(auto_now_add=True) def __str__(self): """返回模型的字符串表示""" return self.text class 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 admin from learning_logs.models import Topic, Entry admin.site.register(Topic) admin.site.register(Entry) -------------------- #### 查看网页,添加条目 #### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 6] 下拉选择对应的Topic,Text添加任意内容 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 7] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 8] 继续添加主题Chess的条目,然后再添加主题Rock Climbing的条目 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 9] -------------------- #### 使用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 admin from 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 path from . import views app_name='learning_logs' urlpatterns = [ # 主页 path('', views.index, name='index'), ] -------------------- #### 编写视图 #### 视图函数接受请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器——这通常是使用定义了网页是什么样的模板实现的。 # vim learning_logs/views.py from django.shortcuts import render from .models import Topic def 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 Log</p> <p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p> > 标签<p></p>标识段落;标签<p>指出了段落的开头位置,而标签</p>指出了段落的结束位置。 * 访问网页: 访问基础URL——`192.168.30.128:8000`,可以看到刚刚定义的模板index.html。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 10] -------------------- ### 创建其它网页 ### 在创建完主页之后,继续创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,我们都将指定URL模式,编写一个视图函数,并编写一个模板。 -------------------- #### 模板继承 #### 创建网站时,几乎都有一些所有网页都将包含的元素。在这种情况下,可编写一个包含通用元素的父模板,并让每个网页都继承这个模板。 * 父模板:首先来创建一个名为base.html的模板,并将其存储在index.html所在的目录中。这个文件包含所有页面都有的元素;其他的模板都继承base.html。 # vim learning_logs/templates/learning_logs/base.html <p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> </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 path from . 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 render from .models import Topic def 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>Topics</p> <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中,项目列表被称为无序列表,用标签`<ul></ul>`表示。 > > 然后使用一个相当于for循环的模板标签,它遍历字典context中的列表topics。在模板中,每个for循环都必须使用`{% endfor %}`标签来显式地指出其结束位置。 > > 在循环中,要将每个主题转换为一个项目列表项。要在模板中打印变量,需要将变量名用双花括号括起来。HTML标签`<li></li>`表示一个项目列表项,在标签对`<ul></ul>`内部,位于标签`<li>`和`</li>`之间的内容都是一个项目列表项。 修改父模板,使其包含到显示所有主题的页面的链接: # vim learning_logs/templates/learning_logs/base.html <p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> - <a href="{% url 'learning_logs:topics' %}">Topics</a> </p> {% block content %}{% endblock content %} > 在到主页的链接后面添加了一个连字符`-`,然后添加了一个到显示所有主题的页面的链接,使用的也是模板标签url。 * 访问网页: 访问基础URL——`192.168.30.128:8000`,可以看到定义的模板index.html及Topics链接。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 11] 点击Topics链接,查看主题 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 12] -------------------- #### 显示特定主题页面 #### 接下来,重复之前步骤,创建一个专注于特定主题的页面——显示该主题的名称及该主题的所有条目。同样的,我们将定义一个新的URL模式,编写一个视图并创建一个模板。 * URL模式: 显示特定主题的页面的URL模式与前面的所有URL模式都稍有不同,因为它将使用主题的id属性来指出请求的是哪个主题。 # vim learning_logs/urls.py """定义learning_logs的URL模式""" from django.urls import path, re_path from . import views app_name='learning_logs' urlpatterns = [ # 主页 path('', views.index, name='index'), # 显示所有的主题 path('topics/', views.topics, name='topics'), # 特定主题的详细页面 re_path(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'), ] 这里用到了python正则表达式,`/(?P<topic_id>\d+)/`与包含在两个斜杠内的整数匹配,并将这个整数存储在一个名为`topic_id`的实参中。`?P<topic_id>`将匹配的值存储到`topic_id`中;而表达式`\d+`与包含在两个斜杆内的任何数字都匹配,不管这个数字为多少位。 发现URL与这个模式匹配时,Django将调用视图函数`topic()`,并将存储在`topic_id`中的值作为实参传递给它。 * 修改视图: # vim learning_logs/views.py from django.shortcuts import render from .models import Topic def 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>\d+)`捕获的值,并将其存储到`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>Topics</p> <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`。 * 访问网页: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 13] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 14] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 15] -------------------- [https_blog.csdn.net_miss1181248983_article_details_90779786]: https://blog.csdn.net/miss1181248983/article/details/90779786 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70]: /images/20211211/afe21a7f2d874ba3ac22ac3a600ab66e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 1]: /images/20211211/ac66599a55644da2bcff322ffefad417.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 2]: /images/20211211/423048e99670445fb34f326a4e6c56b1.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 3]: /images/20211211/b866e668716643b7b35ff1da7667f23d.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 4]: /images/20211211/921a23b7dbfe4fde8496ea8bb1efa0cc.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 5]: /images/20211211/a9a8657b6fba4fc5911c9cdbd4a0d6e0.png [models.py]: http://xn--models-2g0js76l.py [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 6]: /images/20211211/76abfef9da2943588cad5f5d18481e6e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 7]: /images/20211211/eaed57927487408f95f400c2a8461844.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 8]: /images/20211211/b9b79134edf94c41b97035bd421c532c.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 9]: /images/20211211/62e7badfc88647e1ad55bc7deecb9586.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 10]: /images/20211211/5b8aa4d8ac5546b6bf5c7049edc43071.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 11]: /images/20211211/8a545b38cd5b43dd9f683a86596dcd79.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 12]: /images/20211211/d8c0f2f9f3f143bea6f8def906c41efb.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 13]: /images/20211211/548d9be77356491e9308e8241552169b.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 14]: /images/20211211/3933b02103d44b7480fdb624ed112d8a.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pc3MxMTgxMjQ4OTgz_size_16_color_FFFFFF_t_70 15]: /images/20211211/ec852a77a8b74a10aebf038e3338249d.png
还没有评论,来说两句吧...