django2.0学习

django2.0 笔记1

前言

本着学习django机制的想法,暂时忽略对于前段页面的美化,只是达到了解django的目的,为此学习了一些时间。下面是对基于django2.0做的一个非常小型的管理系统,自我认为可以作为初学者的引路篇。


应用工具:

  1. 语言:python3.6,简单的html+css
  2. 数据库:mysql5.7
  3. 软件:Pycharm,Navicat

所用到的python库:
4. django2.0
5. mysqlclient 1.4.6


下面进入实战部分

1.创建django项目

首先要进入python的虚拟环境(这里自行百度,很好解决的),然后执行下面代码:

django-admin startproject booker

这样就可以在虚拟环境的文件夹下创建一个django项目(这个项目含有django的基本配置),目录如下(我的在F盘):

F:.
│  manage.py
│
└─booker
        settings.py
        urls.py
        wsgi.py
        __init__.py

然后可以看到在booker的文件夹里面有一个与项目同命的文件夹,另外一个重要的文件manage.py,这个是操作项目的关键。
其实这已经可以django项目了,cmd进入刚刚创建的项目(而不是项目下同命的文件夹),运行以下代码:

python manage.py runserver

django默认访问网址为:127.0.0.1:8000,这是访问这个网址,如果不出意外,我们可以看到django给我们预先定义的index界面:
django初始化的index
然后我们cmd进入项目文件夹中,创建一个新的app(name:front)应用用于前台展示:

(my_env) F:\ENV>cd booker
(my_env) F:\ENV\booker>python manage.py startapp front

如果没有提示任何信息,就代表成功创建app了,因为没有消息就是最好的消息。
现在整个项目的目录如下:

F:.
│  db.sqlite3
│  manage.py
│
├─booker
│  │  settings.py
│  │  urls.py
│  │  wsgi.py
│  │  __init__.py
│
└─front
    │  admin.py
    │  apps.py
    │  models.py
    │  tests.py
    │  views.py
    │  __init__.py
    │
    └─migrations
            __init__.py

我们将在front文件夹下的文件中写代码,但是在写代码之前,我们还需要做一个事情,就是创建一个用于存储前端页面的文件夹(name:templates),这个文件夹创建在项目目录下,与front同级。
至此,项目结构基本完成。至于项目每个文件有什么用,我会在下面构建代码的过程中进行简单阐述。


2.构建代码

2.1 数据库信息如下:

数据库Navicat展示
其中id我设置的自动增长。
然后我们需要在项目中链接数据库。

2.2 django连接mysql

可以用pycharm打开刚刚创建的项目了,记得pycharm选择自己的虚拟环境。然后打开settings.py文件,找到与数据库相关的信息,django默认的是sqlite3:,没修该的源代码如下:

# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

现在我们要修改数据库的项目配置,具体代码如下所示:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'booker',
        'USER': 'root',
        'PASSWORD': '自己的mysql数据库密码',
        'HOST': '127.0.0.1',
        'POST': '3306',

    }
}

DATABASES 相关的说明如下:

'''
	ENGINE: 数据库引擎,就是我们需要改成mysql,pycharm会自动补全
	NAME: 本项目的数据库名称
	USER: 数据库的用户名
	PASSWORD: 数据库的密码(自己在安装mysql时设置的,如果忘记了百度修改密码方法)
	HOST: mysql的主机名称,127.0.0.1代表本机,因为我自己电脑安装的数据库
	POST: mysql服务器端口号,默认3306
'''

现在数据库配置完成,接下来我们先写views文件和一个前端页面。

2.3 views,URL与前端页面

2.3.1 views.py与urls.py

views.py文件(在自定义的app-front文件夹中)是用于执行业务逻辑,与model.py的交互(或许交互在这里不贴切,应该说是通过model.py访问数据库,两天的时间我未学习到models.py),渲染前端网页(我暂时理解到这里),其实这里我们可以用mysqlclient 访问数据库。(本小型项目也未用到models.py)
首先思考到我们需要一个首页,就是刚刚访问127.0.0.1:8000时候的网页,所以在views.py文件中写首页的试图函数(django在函数def中处理业务逻辑),
刚刚打开views.py时所看到的的代码如下:

from django.shortcuts import render

# Create your views here.

然后我们接着先定义index视图函数:

def index(request):
    pass

然后还需要增加书籍页面以及书籍详情页面的视图函数,如法炮制:

def add_book(request):
    pass


def book_detail(request):
    pass

这里简单说一下,视图函数的第一个参数必须是request,或者你改成其他名字,但是必须有一个变量来接收前端的请求,所以request就不要改成其他的了。
然后接下来我们我们需要配置一下访问的URL,打开urls.py(在项与项目同名的booker文件夹中),未修改之前的代码如下:

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

我们不需要django的admin,所以删掉,另外,我们需要导入front中的views.py文件,具体代码如下:

# 我们先添加两个url
from django.urls import path
from front import views  # 从front导入views

urlpatterns = [
    path('', views.index, name='index'),  # index页面
    path('add_book/', views.add_book, name='add_book'),  # 书籍添加页面
    path('book_detail/', views.book_detail, name='book_detail'),
]

我们现在看一个path的用法:
path中我写的第一个参数为访问时的url,比如访问index(首页)时,我们直接访问127.0.0.1:8000就ok啦,这是path的第一个参数可以写成空字符串;第二个参数是需要处理业务逻辑的视图函数名称,第三个参数可以理解为给这个url起个名字,如果某一天老板要修改URL,而随着我们项目的不断壮大,不可能用到这个URL的地方我们都要修改,那样很蛋疼!起个name,我们就可以直接在这里修改URL,其他地方不用动。
接下来我们测试一下看看能不能跑起来吧,重写写一下views.py文件,引入一个模块:

from django.http import HttpResponse

然后在views.py文件的每个视图函数中增加一行代码:

def index(request):
    return HttpResponse('这是主页')  # 就是增加这行代码,每个视图函数写相应的返回内容
    pass

然后,我们run一下。然后分别访问一下网址:

http://127.0.0.1:8000
http://127.0.0.1:8000/add_book/
http://127.0.0.1:8000/book_detail/

如果没有问题,网页是会显示出我们刚刚写的字符串,比如‘这是主页’,‘这是书籍增添页面’。另外值得注意的是,我们在写path的第一个参数也就是需要访问的URL时,并未写完整,而是写了端口号后面的链接,这里是因为django已经为我们做好了URL的拼接工作。(有兴趣的小伙伴可以看看这里的源码)
我们可以看看HttpResponse这个类的作用是什么,

class HttpResponse(HttpResponseBase):
    """
    An HTTP response class with a string as content.

    This content that can be read, appended to, or replaced.
    """

HttpResponse继承了父类HttpResponseBase,从注释中我们可以看到HttpResponse是一个是以字符串作为内容的http响应类,这也就是我们可以使用它来return给页面一个字符串。
到这里为止,我们基本跑了一个项目,视图和url算是了解了一下,顺便也验证了一下我们项目的正确性。接下来我们要做的事就是简单写一下前端页面。

2.3.2 base.html与base.css

到此为止我们再来看一下项目的目录结构(因为已经用pycharm打开了,pycharm会自动给我建立一些文件,这个无关紧要,现在忽略就好):

F:.
│  db.sqlite3
│  manage.py
│
├─.idea
│  │  booker.iml
│  │  misc.xml
│  │  modules.xml
│  │  workspace.xml
│  │
│  └─inspectionProfiles
│          profiles_settings.xml
│
├─booker
│  │  settings.py
│  │  urls.py
│  │  wsgi.py
│  │  __init__.py
│  │
│  └─__pycache__
│          settings.cpython-36.pyc
│          urls.cpython-36.pyc
│          wsgi.cpython-36.pyc
│          __init__.cpython-36.pyc
│
└─front
    │  admin.py
    │  apps.py
    │  models.py
    │  tests.py
    │  views.py
    │  __init__.py
    │
    ├─migrations
    │      __init__.py
    │
    └─__pycache__
            views.cpython-36.pyc
            __init__.cpython-36.pyc

主要的文件夹以及文件:booker文件夹,front文件夹,manage.py文件。如果我们要写前端页面,我们还需要建立一个文件夹,在于front同级目录中建立一个名为templates的文件夹,这里放我们的前端页面。然后打开settings.py文件,这个我们需要配置一下这个文件夹,以便django可以访问里面的前端文件。在setting.py文件中找到一个名为TEMPLATES的变量,里面有一个**‘DIRS’**,对应的列表为空,然后我们在空列表中加入一行代码:

os.path.join(BASE_DIR, 'templates')
# BASE_DIR 代表的是项目的路径,然后调用join函数把templates加进去,这样django就可以访问到templates文件夹了

接下来,我们写简单的前端页面吧!

  • 首先建立一个base.html页面:
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<nav>
    <ul class="nav">
        <li><a href="{% url 'index' %}">首页</a></li>
        <li><a href="{% url 'add_book' %}">发布图书</a></li>
    </ul>
</nav>
{% block content %}{% endblock %}
</body>
</html>

简单说一下django自带的前端模板语言。这里需要说一个名词DTL:DTL是Django Template Language三个单词的缩写,也就是Django自带的模板语言。
其中包含着对于变量标签过滤器模板结构,以及静态文件等的相关配置。这里不必感觉麻烦,就好像一台洗衣机,我们现在只要会用就ok,先记住怎么洗衣服,等会用了,熟悉了再去了解洗衣机的原理(django源码),之后如果有能力了,再去完善洗衣机功能(django功能完善)。

<li><a href="{% url 'index' %}">首页</a></li>
<li><a href="{% url 'add_book' %}">发布图书</a></li>

这是base.html页面的两个li标签,里面包含了a标签,然后我们需要主要到href属性后面跟着一个 {% %} 这个东西,恭喜你又要接触一个新的知识点了,这就是DTL内置的标签用法。一对花括号,里面跟着一对百分号,在百分号里我们写上url,这就代表我们这里写的是一个链接,然后空格,后面跟上需要访问的html页面,注意是字符串。(这里提醒一下,还记得我们在urls.py中配置URL时path的第三个属性name吗?)。

{% block content %}{% endblock %}

这是一句很神奇的代码,因为这句代码实现了前端页面的继承关系。何为继承呢?在前端页面开发中。有些代码是需要重复使用的。为了简约,可以使用一个比较强大的方式来实现,那就是模版继承。模版继承类似于Python中的类,在父类中可以先定义好一些变量和方法,然后在子类中实现。模版继承也可以在父模版中先定义好一些子模版需要用到的代码,然后子模版直接继承就可以了。并且因为子模版肯定有自己的不同代码,因此可以在父模版中定义一个block接口,然后子模版再去实现。需要注意的是,这个block标签又开始就有结束,不同于DTL中的URL标签,后面我们还会用到DTL的for标签,也同样的有开始就有结束。主要到content没有?这是我们为这个block接口起的名字,你也可以写成别的。
然后我们还差一个css样式表。在写css之前呢,我们还需要建立一个文件夹。在front文件夹中新建一个static文件夹,然后在static文件夹中建立一个front文件夹,在front文件夹中我们存放css等静态文件(为什么在app下创建一个static文件夹,还需要在这个static下创建一个同app名字的文件夹呢?原因是如果直接把静态文件放在static文件夹下,那么在模版加载静态文件的时候就是使用(比如base.css),如果在多个app之间有同名的静态文件,这时候可能就会产生混淆。而在static文件夹下加了一个同名app文件夹,在模版中加载的时候就是使用app/base.html,这样就可以避免产生混淆。)。做好这一步之后呢,关键一步又要来了,打开settings.py文件:

  • 先确保django.contrib.staticfiles已经添加到settings.INSTALLED_APPS中
  • 确保在settings.py中设置了STATIC_URL。(应该在settings.py文件最下面有)
  • 在INSTALLED_APPS变量中添加需要使用的静态文件所在的app。对于这个项目就是添加front.
    之后的INSTALLED_APPS变量如下:
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'front', # 静态文件的所在app
]

现在我们在static的front中新建一个base.css,代码如下:

*{
    margin: 0;
    padding: 0;
}

.nav{
    background: #3a3a3a;
    height: 65px;
    overflow: hidden;
}

.nav li{
    float: left;
    list-style: none;
    margin: 0 20px;
    line-height: 65px;
}

.nav li a{
    color: white;
    text-decoration: none;
}

.nav li a:hover{
    color: lightblue;
}

这里的css代码不做过多的解释,很简单。
到此为止base.html,base.css写好了,剩下的就是写index.html,add_book.html,以及book_detail.html了。先在templates里面定义这三个页面吧!之后开始写页面吗?不着急,我们先反过头来看看views.py。


2.3.2 views.py 的调整

如果你没有更改过views.py文件,应该代码差不多是下面这个样子:

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here

def index(request):
    return HttpResponse('这是主页')
    pass

def add_book(request):
    return HttpResponse('这是书籍增添页面')
    pass
    
def book_detail(request):
    return HttpResponse('这是书籍详情页面')
    pass

接下来跟我一起修改代码吧:

  • 首先我们导入的HttpReesponse是做测试用的,这里不需要,可是删掉。
  • HttpReesponse删除之后,每个视图函数的return语句删掉。
  • 我们想要调用数据库的数据,这里就需要调用一个python操作mysql的库,我选用的是mysqlclient 。
    调整之后的代码如下所示:
from django.shortcuts import render
from django.db import connection  # 操作数据库

# Create your views here.

def index(request):
    pass
    
def add_book(request):
    pass
    
def book_detail(request):
    pass

调用connection之后,在views.py 文件中,写入下面这个函数:

def get_cursor():
    return connection.cursor()

先记住一个词:游标,我们下面就是使用游标来操作真正操作数据库了。
重写index视图函数:

def index(request):
    cursor = get_cursor()
    cursor.execute("select * from book")  
    books = cursor.fetchall()
    return render(request, 'index.html', context={'books': books})
    pass
'''
	cursor.execute("select * from book") 这句代码就是通过sql语句操作数据库;
	books = cursor.fetchall()   fetchall()方法是获取所有的查询结果,其返回对象是这种形式[(1,'高等数学','汤家风'),(...)],就是一个列表里存放元组,每个元组保存的是查询的字段结果
	相对的fetchone()方法获取一个结果
	return render(request, 'index.html', context={'books': books}) 我们下面看一下render:
'''
# render 用于模板渲染,具体了解一下这个源代码:
def render(request, template_name, context=None, content_type=None, status=None, using=None):
    """
    Return a HttpResponse whose content is filled with the result of calling
    django.template.loader.render_to_string() with the passed arguments.
    """
    content = loader.render_to_string(template_name, context, request, using=using)
    return HttpResponse(content, content_type, status)
# 第一个参数必须是request,或者是视图函数的第一个参数,你可以起别的名字,但是视图函数的第一个参数必须和render方法的第一个参数相同,
# 第二个参数是template_name,也就是你要将结果return到哪个html文件中,
# 第三个context=None,代表可有可无,如果你需要从数据库中将查询结果返回到前端页面中,那么久需要这个context,但是context必须是一个字典。

写到这里如果不出意外,pycharm会提示我们没有index.html文件,那么接下里重新回到前端页面中吧!


2.3.2 index.html建立

index.html如下:

{% extends 'base.html'  %}
{% block content %}
    <table>
        <thead>
            <tr>
                <th>序号</th>
                <th>书名</th>
                <th>作者</th>
            </tr>
        </thead>
        <tbody>
            {% for book in books %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td><a href="{% url 'book_detail' book_id=book.0 %}">{{ book.1 }}</a></td>
                    <td>{{ book.2 }}</td>
                </tr>
            {% endfor %}

        </tbody>
    </table>
{% endblock %}

还记得我们有个base.html吗。思考两个问题,1.为什么起名叫base.html;2.模板继承是什么来着?{% extends ‘base.html’ %} 就代表本页面继承base.html所有东西,还记得那个block接口吗?单独属于index.html的东西就在这个接口中去写。
我们将数据库查询的结果保存在render的第三个参数context中,然后传递给了index.html页面,在前端页面中我们可以直接使用context中字典的键(比如books),还记得fetchall()方法返回的是什么类型吗?这里我们用一个for循环来遍历里面的元组,{{ forloop.counter }}是DTL使用变量的方法(先记住会用),这个forloop.counter表示下标从1开始,相对的forloop.counter0下标从0开始,第二个td标签我们用来显示书籍的名称,books是一个列表,book是一个元组,元组是这样的(id,‘书籍名称’,‘作者’),我们循环遍历books,得到每个元组,那么怎么的到元组里的值呢?有python基础的小伙伴可能会说book[下标],但是django中不是这样的,django使用的是book.下标,记住就好。因为我们要访问书籍的详情页面,我们需要一个a标签,访问书籍详情页面时,我们需要根据id来获取对应书籍信息,所以我们还需要穿一个参数,book_id=book.0,这个以备detail页面使用。(自己在数据库中写点信息,我写的是(1,‘高等数学’,‘汤家凤’)),如果到这里不出意外地话,run一下项目,你会看到这个:
错误信息
对,报错了,提示我们在url中book_id未被接收,下面修改一下urls.py文件中的book_detail这url,修改如下:

path('book_detail/<int:book_id>/', views.book_detail, name='book_detail'),
# 尖括号里面写数据类型然冒号加上前台传过来的信息,这里的book_id 就是index页面中这个句代码传过来的:
# <td><a href="{% url 'book_detail' book_id=book.0 %}">{{ book.1 }}</a></td>
# 注意到代码里的book_id=book.0了吗?

重新run一下,就是下面这个结果了:
index.html
然后点击一下高等数学这个超链接,然后就是报错了:
报错
根据提示信息想想为什么报错,我们在点击超链接的时候,实际上根据urls.py我们访问的http://127.0.0.1:8000/book_detail/1/ 这个url,然后进入相应视图函数去进行业务处理,返回来看看我们这个对应的视图函数:

def book_detail(request, ):
    pass

这里我们没有写这个前端返回的参数,所以报错了,修改如下,并验证一下想法是否正确(这里重新导入一下HttpResponse):

def book_detail(request, book_id):
    text = '您访问的书籍id是%s' % book_id
    return HttpResponse(text)
    pass

现在重新run一下,就发现可以跑通了。


2.3.3 其他视图与对应的HTML

到这里基本就ok了,下面就是继续写代码啦:

  • 书籍详情视图:
def book_detail(request, book_id):
    cursor = get_cursor()
    cursor.execute("select * from book where id=%s" % book_id)
    book = cursor.fetchone()
    return render(request, 'book_detail.html', context={'book': book})
    pass
  • 书籍详情页面(templates下新建book_detail.html):
{% extends 'base.html' %}
{% block content %}
    <p>书名:{{ book.1 }}</p>
    <p>作者:{{ book.2 }}</p>
{% endblock %}

  • 添加图书视图函数:
from django.shortcuts import render, redirect, reverse
# reverse()方法可以urls.py中path第三个参数name反向得到url
# redirect()方法可以重定向 

def add_book(request):
    if request.method == 'GET':
        return render(request, 'add_book.html')
    else:
        name = request.POST.get("name")
        author = request.POST.get("author")
        cursor = get_cursor()
        cursor.execute("insert into book(id,name,author) values(null,'%s','%s')" % (name, author))
        return redirect(reverse('index'))
    pass
  • 添加书籍页面(templates下新建add_book.html):
{% extends 'base.html' %}
{% block content %}
    <form action="" method="post">
        <table>
            <tbody>
                <tr>
                    <td>书名:</td>
                    <td><input type="text" name="name"></td>
                    <td>作者:</td>
                    <td><input type="text" name="author"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="提交"></td>
                </tr>
            </tbody>
        </table>
    </form>
{% endblock %}

到这里run一下:
CSRF
因为在添加书籍页面中我们存在表单提交,这会触发django的CSRF防护,这里先注释掉CSRF代码,在settings中的MIDDLEWARE注释掉一下代码:

'django.middleware.csrf.CsrfViewMiddleware',

再重新run一下:
添加书籍
单击提交,会自动返回index页面,因为我们在add_book的视图函数中重定向了:
index
到这里结束,我们实现了增删查改的增与查功能,剩下的照猫画虎自己可以完成。


记录一下我的当前时间吧:

In [1]: from datetime import datetime

In [2]: datetime.now()
Out[2]: datetime.datetime(2020, 1, 29, 14, 54, 46, 379241)

In [3]:exit

发布了5 篇原创文章 · 获赞 0 · 访问量 365

猜你喜欢

转载自blog.csdn.net/qq_33694648/article/details/104103073