学习Django(1)

先把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有很大的区别,具体看下图:


2019226-172748.jpg

可以看到两个文件夹内容完全不同。可以这么理解,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,现在可以显示如下:


2019228-172334.jpg

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 %}这个告诉了我们,这个循环内容为空的时候显示什么东西。


2.jpg

这时候,上面第五步的第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 作用是将包含换行符的长条目转换为浏览器能够理解的格式。这一切完成之后,显示内容如下图:


3.jpg

第六:总结

总得缕了一下,django框架可以把数据库,网页结合起来,就不用和javaSE那样分开做了,目前这个案例最傻的就是命名太相似,这样要深刻理解代码中写的到底是指什么,代码互相调用,文件互相调用要深刻理解,下面是我整理的调用流程:


4.jpg

下面是发现的一个容易出错的问题,在<a>标签页内,'url'这个和之后的内容一定要分开,如果和下图一样连着,就会出现下面报错!!!


6.jpg
7.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容