先把github链接放上来:
https://github.com/q100036q/python_demo_learning_logs
第一:安装Django
在windows系统下安装和使用Django很简单,而且为了创建新的工程项目,可以创建一个虚拟的环境来独立的编程。
创建新的虚拟项目和安装Django的流程如下:
1.新建一个工程路径,打开控制台,切换到这个路径下。
2.输入下面代码创建一个虚拟环境:
python -m venv ll_env
3.激活虚拟环境,有两种方法:第一是直接输入:
ll_env\Scripts\activate
上述代码进行创建,第二种是,打开ll_env\Scripts文件夹,按住shift点击鼠标右键,打开命令窗口再把activate.bat拖进去。这种方法适合第一次之后的打开,就不用再命令行手动操作了。
4.创建并激活虚拟环境后,就可安装Django了,输入下面代码:
pip install Django
第二:在Django中创建项目
1.创建项目路径,用下面创建一个名为learning_log 的文件夹:
django-admin.py startproject learning_log .
可是经过测验,上面教程中的代码无效,在网上只能找到另一种方案,输入下面代码:
django-admin startproject learning_log .
最后的点不能省略,这个命令末尾的句点让新项目使用合适的目录结构,manage.py这个文件会和ll_env文件夹同级,否则将会放进learning_log 文件夹下。
现在在ll_env文件夹同级目录下,新出现了learning_log文件夹和manage.py文件。
2.创建数据库。使用manage.py文件进行数据库的迁移指令,可以新建一个文件数据库:
python manage.py migrate
这时候在ll_env文件夹同级目录下又出现了一个名为db.sqlite3的数据库文件。
3.查看项目是否能执行。
python manage.py runserver
上述代码能够运行一个服务器,并显示出来url路径,这时候我们可以通过浏览器输入它来访问这个本地服务器。
第三:创建一个应用程序
1.在第二步运行了一个服务器的情况下,重新再manage.py的路径下打开一个命令行窗口,并执行激活(第一步的第3条)。
2.执行命令startapp,它可以创建一个在同级路径下的应用程序。
python manage.py startapp learning_logs
可以看到,文件夹路径下多了一个名为learning_logs的文件夹,这个和之前第二步第1条创建的learning_log有很大的区别,具体看下图:
可以看到两个文件夹内容完全不同。可以这么理解,learning_log是我们控制中心,存放一些配置相关的内容,而learning_logs是我们自己编写程序的部分,用来管理数据。
3.定义模型,其实也就是创建各种各样的类,来达到目的,目前这个工程主要是用来保存数据,这里再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):
if len(self.text) > 50:
return self.text[:50] + '...';
else:
return self.text;
models.CharField是储存字符或文本数据,models.TextField类似,但是是没有长度限制,显示在web上出来是一个文本框。
1)这里重点一个是on_delete = models.CASCADE这段代码,如果不加会报错,主要是因为Django更新至2.0以上版本了。
2)方法str() 告诉Django,呈现条目时应显示哪些信息。
3)我们在Entry 类中嵌套了Meta 类。Meta 存储用于管理模型的额外信息,在这里,它让我们能够设置一个特殊属性,让Django在需要时使用Entries 来表示多个条目。如果没有这个类, Django将使用Entrys来表示多个条目。(这段还没搞懂)。
4)Entry的第一个属性topic 是一个ForeignKey 实例。外键是一个数据库术语,它引用了数据库中的另一条记录;这些代码将每个条目关联到特定的主题。每个主题创建时,都给它分配了一个键(或ID)。需要在两项数据之间建立联系时,Django使用与每项信息相关联的键。
4.激活模型,要使用模型,必须让Django将应用程序包含到项目中。这里需要用learning_log中的settings.py文件,并在INSTALLED_APPS里包含learning_logs内容:
#settings.py
INSTALLED_APPS = (
--snip--
'django.contrib.staticfiles',
# 我的应用程序
'learning_logs',
)
5.接下来,修改数据库,使其能保存我们在models.py中定义的模型:
python manage.py makemigrations learning_logs
接着进行数据库的迁移,为我们的新模型去创建一个表:
python manage.py migrate
6.Django管理网站,首先添加一个超级管理员的权限,这样能在web上修改添加内容:
python manage.py createsuperuser
按照提示输入自己的信息即可。
接着,向管理网站注册模型,之前定义的两个模型,在这里要进行注册,注册的代码写在admin.py中:
#admin.py
from django.contrib import admin;
from learning_logs.models import Topic,Entry;
admin.site.register(Topic);
admin.site.register(Entry);
最后就可以访问http://localhost:8000/admin/ ,输入账号密码进入后台,此时可以针对Topic和Entry进行编辑了,由于绑定外键的关系,一定要有一个Topic内容,才能去添加Entry。
7.Django shell,可以使用shell来探索存储在项目数据库中的数据。
python manage.py shell
上面代码可以运行到shell中,运行下面脚本,查看下我们数据库的内容:
from learning_logs.models import Topic
topics = Topic.objects.all()
for topic in topics:
print(topic.id, topic)
t = Topic.objects.get(id=1)
t.text
t.entry_set.all()
最后这条t.entry_set.all(),为通过外键关系获取数据,可使用相关模型的小写名称、下划线和单词set。
8.遇到的问题:
1)每次修改模型(manage.py文件),要重启shell;
2)有的时候如果增加了新模型,要去修改admin.py增加新的注册。
3)一般情况下,不需要重启服务器,但是如果一直不响应的情况下,可以ctrl+c关闭,在使用第二步的第3条重启。
4)关闭shall的方法:ctrl+z再回车即可。
第四:映射URL
简单的说就是设置打开浏览器的页面。这里先修改默认的主页。
1.修改主目录url内容,打开项目主文件夹learning_log中的文件urls.py,这里添加内容:
#urls.py(learning_log/urls.py)
from django.contrib import admin;
from django.urls import path,include;
from django.conf.urls import url;
urlpatterns = [
path('admin/', admin.site.urls),
# path(r'',include('learning_logs.urls',namespace = 'learning_logs')),
url(r'',include('learning_logs.urls',namespace = 'learning_logs'))
]
在Django1.11中路由函数为url(),在Django2中路由函数改成了path(),不过路由函数向下兼容,在Django2中同样可以使用url()函数,这里列出两种写法,注意引入对应的模块,这里加载指向learning_logs.urls这个文件,namespace只是为了和别的url作区分。
2.添加新目录下的url,填写现在我们需要在文件夹learning_logs中创建另一个urls.py文件,内容如下:
#urls.py
from django.conf.urls import url;
from . import views;
app_name='learning_logs'
urlpatterns = [
url(r'^$',views.index,name = 'index'),
]
我们来看看正则表达式r'^$' 。其中的r 让Python将接下来的字符串视为原始字符串,而引号告诉Python正则表达式始于和终于何处。脱字符(^ )让Python查看字符串的开头,而美元符号让Python查看字符串的末尾。总体而言,这个正则表达式让Python查找开头和末尾之间没有任何东西的URL。Python忽略项目的基础URL(http://localhost:8000/),因此这个正则表达式与基础URL匹配。
url() 的第二个实参指定了要调用的视图函数。请求的URL与前述正则表达式匹配时,Django将调用views.index (这个视图函数将在下一节编写)。第三个实参将这个URL模式的名称指定为index,让我们能够在代码的其他地方引用它。每当需要提供到这个主页的链接时,我们都将使用这个名称,而不编写URL。
3.编写视图内容,视图函数接受请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器,这个依据模板代码来实现不同的效果,这里我们修改views.py文件:
#views.py
from django.shortcuts import render
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
URL请求与我们刚才定义的模式匹配时,Django将在文件views.py中查找函数index() ,再将请求对象传递给这个视图函数。
4.编写网页模板。在文件夹learning_logs中新建一个文件夹,并将其命名为templates。在文件夹templates中,再新建一个文件夹,并将其命名为learning_logs。在最里面的文件夹learning_logs中,新建一个文件,并将其命名为index.html,再在这个文件中编写如下代码:
#index.html
<p>Learning Log</p>
<p>Learning Log helps you keep track of your learning, for any topic you'relearning about.</p>
这样就完成了主页的编辑。
5.几个要点:
1)urls.py文件中的urlpatterns不能写错,否则会报错。
2)新创建的子文件夹的urls.py文件需要添加下面这行代码,否则会报错:
app_name='learning_logs'
这是因为之前定义了namespace属性, [app_name]代表你的应用的名称。
3)这篇代码编写完成后不用重启服务器,在setting.py中设置了DEBUG = True,浏览器会自动刷新我们刚保存的代码。但是,实际运用中DEBUG不能设置为true。
第五:创建其它网页:
这段是对网页和之前的数据绑定,把之前存入数据库的内容展示出来。
1.模板继承,可以创建一个父模板,让其他模板(网页代码)都继承它,可以方便统一修改。
下面,为了给几个子网页都添加一个统一的内容,父模板仅仅制作带链接的标题,可以让子模板点击回到主页。base.html内容如下:
#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 %}
有网页制作相关知识的就知道<p>是一个段落标签,<a>是一个超链接标签,href指向一个链接,这里{%%}是一个模板标签,内容就指向了learning_logs下的index文件,即主页。{% block content %}{% endblock content %}是一对占位符,具体内容由子模板指定。中间这段被注释的代码在后面显示次级界面的时候要解开注释。现在重新编辑index.html文件,让他继承父模板base.html:
#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 表示继承的路径内容。占位符内容就是这个子模板独有的内容。它因为继承自base.html,现在可以显示如下:
2.显示主题页面,为了增加新的下一级别的网页,这里要去修改urls.py文件,增加了一行内容:
#urls.py
from django.conf.urls import url;
from . import views;
app_name='learning_logs'
urlpatterns = [
url(r'^$',views.index,name = 'index'),
url(r'^topics/$',views.topics,name = 'topics'),
]
正则表达式中添加了topics/这一段,说明我们现在匹配的网址应该是:http://127.0.0.1:8000/topics/。其URL与该模式匹配的请求都将交给views.py中的函数topics() 进行处理。接下来,我们去这个文件中把它添加上:
#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)
这里是一个难点,可能都已经忘记了之前我们做的操作了,这时候翻上去看第三步的第3段,我们在models.py文件内写下了Topic这个模型,并且定义了name和date_added这个属性,order_by对其排序,取出所有的值,然后保存为一个字典文件,并命名为context再通过render传递到topics.html里接收。现在当然是创建一个名为topics.html的页面文件了:
#topics.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>
<!-->注意,这段在下面创建topic.html的时候放开注释,为的是创建一个指向下一层级的超链接,并且将topic.id 传递到topic.html文件中
<a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
<-->
{{ topic }}
</li>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock content %}
依照下图,可以看出上面代码说的到底是啥,<ul><li>分别代表无序列表和列表项的标签, {% for%}和 {% endfor %}用来当做一个for循环,读取views.py传递过来的内容,并做成超链接,{{ topic }} 是将每一项名称都显示,不是使用一对,而是两对,不然显示的内容是:{ topic }。{% empty %}这个告诉了我们,这个循环内容为空的时候显示什么东西。
这时候,上面第五步的第1段中的注释代码要解开。
3.显示对应主题的内容。
之前,我们在定义文件的标题的同时也保存了相应的内容,这里我们点击每个列表项之后,打开新的页面去显示它。为了打开新的页面,必须去urls.py增加新的配置:
#urls.py
from django.conf.urls import url;
from . import views;
app_name='learning_logs'
urlpatterns = [
url(r'^$',views.index,name = 'index'),
url(r'^topics/$',views.topics,name = 'topics'),
url(r'^topics/(?P<topic_id>\d+)/$',views.topic,name = 'topic'),
]
最后一行新增内容:在r'^$'直接加入了topics/(?P<topic_id>\d+)/这么一句正则表达式,作用就是匹配到http://localhost:8000/topics/1/这样的URL,d+表示任意数字,(?P)为命名捕获,是捕获内容储存到topic_id中,这个是python专有的语法。接下来还是根据这里设置的views.topic去views.py文件中新增topic函数:
#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)
topic函数传入刚刚捕获到的参数topic_id,然后根据之前在shell里学习的方法,去数据库中读取数据,再通过date_added倒序排序,entry_set读取出我们之前存入数据库中的内容(忘记的话参考第三步的第7条),存进字典新增一项。最后通过render一起传给topic.html。
注意,这时候要把第五步第2段中topics.html文件中的注释解开。
这时候创建这个文件:
#topic.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics:{{topic}}</p>
<p>Entries:</p>
<ul>
{% for entry in entries %}
<li>
<p>{{ entry.date_add|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的值,这个在views.py里获得了。然后通过for循环读取entries里面的内容,并且对应的格式化显示,|符合是一个过滤器,linebreaks 作用是将包含换行符的长条目转换为浏览器能够理解的格式。这一切完成之后,显示内容如下图:
第六:总结
总得缕了一下,django框架可以把数据库,网页结合起来,就不用和javaSE那样分开做了,目前这个案例最傻的就是命名太相似,这样要深刻理解代码中写的到底是指什么,代码互相调用,文件互相调用要深刻理解,下面是我整理的调用流程:
下面是发现的一个容易出错的问题,在<a>标签页内,'url'这个和之后的内容一定要分开,如果和下图一样连着,就会出现下面报错!!!