0.0 规范
我要编写一个名为“学习笔记”的 Web 应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。“学习笔记”的主页对这个网站进行描述,并邀请用户注册或登录。用户登录后,可以创建新主题、添加新条目以及阅读既有的条目。
目录 ll_project 包含 4 个文件, 其中最重要的是 settings.py 、urls.py 和 wsgi.py 。文件 settings.py 指定 Django 如何与系统交互以及如何管理项目。
在开发项目的过程中,我们将修改其中的一些设置,并添加一些设置。
文件 urls.py 告诉 Django,应创建哪些网页来响应浏览器请求。
文件 wsgi.py 帮助 Django 提供它创建的文件,名称是 web server gateway interface(Web 服务器网关接口)的首字母缩写。
1.0 创建环境
1.1 创建虚拟环境
在独立的项目文件夹下运行
python -m venv ll_env python -m ensurepip --default-pip
将会创造一个ll_env
文件夹
可以使用下面的命令激活虚拟环境。激活虚拟环境后,安装的模组将只在虚拟环境中生效,而不干扰到电脑上Python的模组
source ll_env/bin/activate source ll_env/Scripts/activate (ll_env) work_directory$
使用deactive
取消激活虚拟环境
1.2 安装配置Django
pip install --upgrade pip pip install django django-admin startproject ll_project . python manage.py migrate python manage.py runserver
Django手册: https://docs.djangoproject.com/en/4.1/ref/models/fields/
1.3 创建和配置App
python manage.py startapp learning_logs(app_name)
python manage.py makemigrations learning_logs(app name) python manage.py migrate
每当需要修改“学习笔记”管理的数据时,都采取如下三个步骤:修改
models.py ,对 learning_logs 调用 makemigrations,以及让 Django迁移项目。
1.4 创建管理员及注册模型到admin页面
python manage.py createsuperuser ll_admin, Abc123
from django.contrib import adminfrom .models import Model1, Model2 admin.site.register(Model1)
1.5 定义模型Models
打开app_name/models.py
class Model_name1 (models.Model): """Document""" text = models.TextField() def __str__ (self ): """Return a string representation of the model.""" return self .text class Model_name2 (models.Model): """Document""" content = models.TextField(max_length=200 ) something_else = models.ForeignKey(Model_name1, on_delete=models.CASCADE) def __str__ (self ): """Return a string representation of the model.""" return self .content
1.6 激活模型
在settings.py
下找到INSTALLED_APPS
并添加App名称
INSTALLED_APPS = [ 'app_name' , 'django.contrib.admin' , --snip-- ]
1.7 Shell命令行
$ python manage.py shell from learning_logs.models import TopicTopic.objects.all () topics = Topic.objects.all () for topic in topics: print (topic.id , topic) t = Topic.objects.get(id =1 ) t.text t.date_added t.entry_set.all ()
2.0 制作网页
使用 Django 创建网页的过程分为三个阶段:定义 URL,编写视图,以及编写模板。按什么顺序完成这三个阶段无关紧要,但在本项目中,总是先定义 URL 模式。URL 模式 描述了 URL 的构成,让 Django 知道如何将浏览器请求与网站 URL 匹配,以确定返回哪个网页。
2.1 制作主页
增加配置文件,在ll_project
中编辑urls.py
from django.urls import include urlpatterns = [ path('admin/' , admin.site.urls), path('' , include('app_folder_name.urls' )), ]
创建并编辑app_folder_name/urls.
"""Defines URL patterns for learning_logs.""" from django.urls import pathfrom . import viewsapp_name = 'learning_logs' urlpatterns = [ path('' , views.index, name='index' ), ]
编写views.py
from django.shortcuts import renderdef index (request ): """The home page for Learning Log.""" return render(request, 'app_floder_name/index.html' )
创建tmplates/app_floder_name
文件夹,并创建index.html
文件
<p > Learning Log</p > <p > Learning Log helps you keep track of your learning, for any topic you'reinterested in.</p >
2.2 制作网页模板
创建base.html
<p > <a href ="{% url 'learning_logs:index' %}" > Learning Log</a > </p > {% block content %}{% endblock content %}
使用base.html
模板
{% extends 'learning_logs/base.html' %} {% block content %} <p > Learning Log helps you keep track of your learning, for any topic you're interested in.</p > {% endblock content %}
2.3 制作Topic与Entry网页
2.3.1 Topics
修改urls.py
,创建topics
界面
urlpatterns = [ path('' , views.index, name='index' ), path('topics/' , views.topics, name='topics' ), ]
修改views.py
,创建topics
方法
from .models import Topic def topics (request ): """Show all topics.""" topics = Topic.objects.order_by('date_added' ) context = {'topics' : topics} return render(request, 'learning_logs/topics.html' , context)
创建topics.html
界面
{% extends 'learning_logs/base.html' %} {% block content %} <p>Topics</p> <ul> {% for topic in topics %} <li>{{ topic.text }}</li> {% empty %} <li>No topics have been added yet.</li> {% endfor %} </ul> {% endblock content %}
修改base.html
,添加链接
<p> <a href="{% url 'learning_logs:index' %}" >Learning Log</a> - <a href="{% url 'learning_logs:topics' %}" >Topics</a> </p>
2.3.2 Topic
修改urls.py
,创建topic
界面
修改views.py
,创建topic
方法
创建topic.html
界面
修改topics.html
,添加链接 (不是修改base.html
)
urlpatterns = [ --snip-- path('topics/<int:topic_id>/' , views.topic, name='topic' ), ] 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)
{% extends 'learning_logs/base.html' %} {% block content %} <p > Topic: {{ topic.text }}</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 %} {% for topic in topics %} <li > <a href ="{% url 'learning_logs:topic' topic.id %}" > {{ topic.text }}</a > </li > {% empty %}
1.1 第一阶段总结
构建learning_logs
的过程基本上是在抄代码,只有到做课后练习,完成pizzas_project
的时候才真正在学习。例如为什么import Topic
而不是Entry
,在我课后练习的时候就给我带来了一个无法运行网页的代价:不理解subsequence_set
是怎么来的,就不能够成功地导入Pizza
模组并成功设置toppings
参数;不理解.order_by()
方法建立在什么基础上,不阅读手册,就想不到在不是博客,而是菜单的pizza项目中使用.all()
理解是那么的重要,它几乎占据了学习的全部:理解过后就只剩计算了。而学习的乐趣也大多在于这个理解和融会贯通。
最终我明白:正是在错误中我得以学习,不要畏惧错误。正如CSAPP所说:错误地使用内存,最好的结果是程序马上崩溃,最坏的结果是程序运行一段时间才出现不知道哪里冒出来的问题。让我多多崩溃,这是相对最好的结果。
2024/6/25:有一些小细节也会导致错误,例如DateField和DateTimeField是不一样的
2024/6/26:html -> views.py字典 -> models.py定义字段
3.0 用户账户
3.1 让用户添加Topics
添加新主题,四步走
创建app_folder/forms.py
,添加表单
修改urls.py
,添加网页
修改views.py
,添加定义的函数
创建html模板
链接到页面
from django import formsfrom .models import Topicclass TopicForm (forms.ModelForm): class Meta : model = Topic fields = ['text' ] labels = {'text' : '' } widgets = {'text' : forms.Textarea(attrs={'cols' : 80 })} urlpatterns = [ path('new_topic/' , views.new_topic, name='new_topic' ), ] from django.shortcuts import render, redirectfrom .models import Topicfrom .forms import TopicFormdef new_topic (request ):"""添加新主题""" if request.method != 'POST' : form = TopicForm() else : form = TopicForm(data=request.POST) if form.is_valid(): form.save() return redirect('learning_logs:topics' ) context = {'form' : form} return render(request, 'learning_logs/new_topic.html' , context)
{% extends "learning_logs/base.html" %} {% block content %} <p > Add a new topic:</p > <form action ="{% url 'learning_logs:new_topic' %}" method ='post' > {% csrf_token %} {{ form.as_div }} <button name ="submit" > Add topic</button > </form > {% endblock content %} {% extends "learning_logs/base.html" %} {% block content %} <p > Topics</p > <ul > --snip-- </ul > <a href ="{% url 'learning_logs:new_topic' %}" > Add a new topic</a > {% endblock content %}
3.2 新增、修改entries
# forms.py from django import forms from .models import Topic, Entry class TopicForm(forms.ModelForm): --snip-- class EntryForm(forms.ModelForm): class Meta: model = Entry fields = ['text'] labels = {'text': ''} widgets = {'text': forms.Textarea(attrs={'cols': 80})} # urls.py urlpatterns = [ --snip-- # 用于添加新条目的页面 path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'), ] # views.py from django.shortcuts import render, redirect from .models import Topic from .forms import TopicForm, EntryForm --snip-- def new_entry(request, topic_id): """在特定主题中添加新条目""" topic = Topic.objects.get(id=topic_id) if request.method != 'POST': # 未提交数据:创建一个空表单 form = EntryForm() else: # POST 提交的数据:对数据进行处理 form = EntryForm(data=request.POST) if form.is_valid(): new_entry = form.save(commit=False) new_entry.topic = topic new_entry.save() return redirect('learning_logs:topic', topic_id=topic_id) # 显示空表单或指出表单数据无效 context = {'topic': topic, 'form': form} return render(request, 'learning_logs/new_entry.html', context)
{% extends "learning_logs/base.html" %} {% block content %} <p > <a href ="{% url 'learning_logs:topic' topic.id %}" > {{ topic }}</a > </p > <p > Add a new entry:</p > <form action ="{% url 'learning_logs:new_entry' topic.id %}" method ='post' > {% csrf_token %} {{ form.as_div }} <button name ='submit' > Add entry</button > </form > {% endblock content %} <p > Entries:</p > <p > <a href ="{% url 'learning_logs:new_entry' topic.id %}" > Add new entry</a > </p >
urlpatterns = [ --snip-- path('edit_entry/<int:entry_id>/' , views.edit_entry, name='edit_entry' ), ] from django.shortcuts import render, redirectfrom .models import Topic, Entryfrom .forms import TopicForm, EntryForm--snip-- def edit_entry (request, entry_id ):"""编辑既有的条目""" entry = Entry.objects.get(id =entry_id) topic = entry.topic if request.method != 'POST' : form = EntryForm(instance=entry) else : form = EntryForm(instance=entry, data=request.POST) if form.is_valid(): form.save() return redirect('learning_logs:topic' , topic_id=topic.id ) context = {'entry' : entry, 'topic' : topic, 'form' : form} return render(request, 'learning_logs/edit_entry.html' , context)
{% extends "learning_logs/base.html" %} {% block content %} <p > <a href ="{% url 'learning_logs:topic' topic.id %}" > {{ topic }}</a > </p > <p > Edit entry:</p > <form action ="{% url 'learning_logs:edit_entry' entry.id %}" method ='post' > {% csrf_token %} {{ form.as_div }} <button name ="submit" > Save changes</button > </form > {% endblock content %}
3.3 让用户登录、注册
3.4 让用户只能看见自己的topic
4.0 美化页面
4.1 安装并启用bootstrap5
(ll_env)learning_log$ pip install django-bootstrap5
settings.py
INSTALLED_APPS = [ 我的应用程序 'learning_logs' ,'accounts' , 第三方应用程序 'django_bootstrap5' ,
5.0 部署
生成配置文件requirements.txt
$ pip freeze > requirements.txt $ pip install -r requirements.txt
YAML (YAML Ain’t Markup Language)