独立完成一个在线网站记录之初识Django,配置静态文件,编写models

之前的内容晚上按照记录来整理。

我们新建工程以后要考虑的因素有很多:

  • 主目录下有一个templates文件夹,这里面我们存放的是.html文件。
  • 因为要存储一些静态的文件,比如css文件(样式文件),js文件等等,所以要新建一个文件夹statics存放这些静态的文件。
  • 我们还有一些日志需要记录,所以新建一个log文件夹存放日志文件。
  • 因为是一个web网站,有用户的操作,所以要新建一个media的文件夹存放用户上传的文件。
  • 还有就是当一个web项目越来越大的时候,应用会越来越多,如果都挂在项目文件夹下面的目录中,将会有很多的文件夹,所以要建立一个apps的文件夹用来存放应用。

但是遇到一个新的问题就是import的时候比较难指明全路径。该怎么解决呢?好好想一下。


跟着老师的讲课的进度接着做,首先有一个.html的文件,这个文件中既有html代码,也有css代码。

将这个文件分离出来,html代码部分,可以放在templates文件夹下的.html文件中。css代码的部分,先在statics文件夹下面新建一个css文件夹,css中新建style.css文件,将css代码copy到style.css文件中。

接下来修改数据库,这一步做过好多次了,直接略过。


这里老师讲到了一个知识点,就是在写views.py文件里面的视图函数的时候,参数是request,这是一个httprequest的对象,关于这个知识点,参考链接:http://www.cnblogs.com/MnCu8261/p/5871085.html

settings中的静态文件路径的配置。

添加一个STATICFILES_DIRS = …,比如这个项目中的代码:

在settings.py中:

1
2
3
4
5
6
7
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)

在对应的前段界面中:

1
2
3
4
5
6
7
8
9
{% load staticfiles %}
# 在用到静态文件中的时候,我们使用这样的形式
# 在我做的这个在线网站中,目前有四种静态文件,下面分别是每种的例子
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
<div class="close jsCloseDialog"><img src="{% static 'images/dig_close.png' %}"/></div>
<script src="{% static 'js/jquery.min.js' %}" type="text/javascript"></script>
{% static 'img/...' %}

那为什么这么做呢?

下面这段话有待考证:
==我们给/static/(放置静态文件的路径)设置了一个别名,这样即使更改了放置静态文件的路径的,只要去修改settings.py文件的一处就可以很方便的修改,可维护性比较好。==

我开发的时候使用的是python的IDE:Pycharm, 里面可以将app设置成source root,但是我们使用命令行runserver的时候,发现找不到app,那么我们要设置文件的绝对路径就是source root,那么怎么做呢?

这里有一个知识点,就是Python如何获得文件的绝对路径。使用函数os.path()。
1
2
3
4
5
import os
import sys
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

使用sys.path的insert()方法,使用os.path.join()方法。

database的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '*********',
'USER': 'root',
'PASSWORD': '*************',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
templates的配置:
1
2
3
4
5
6
7
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
...
}
]

migration会帮我们生成或者修改数据库的表。把前端给的文件拆分。

根据前端页面分析业务。

数据模型的编写。

Django的ORM。就是平时使用的makemigrations和migrate.

什么是ORM?

ORM也就是Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。

ORM优缺点:

优点:摆脱复杂的SQL操作,适应快速开发;让数据结构变得简洁;数据库迁移成本更低(如从mysql->oracle)

缺点:性能较差、不适用于大型应用;复杂的SQL操作还需通过SQL语句实现

参考链接:http://www.cnblogs.com/caseast/articles/4806213.html


Django model的设计

Django的model让创建数据库像创建类一样的简单。

在models.py 文件夹中

CharField必须有一个最大长度,verbose_name可以看成是一个注释,在后台管理(Django.admin)中,修改后台数据的时候会显示出verbose_name的值,否则就会显示*object。

其他的Field,比如邮箱用的是EmailField()

在python2.X中和3.X中字符操作的差别。这个不是很清楚,但是python3中更加的简单:

1
2
def __str__(self):
return self.username

class Meta:

参考链接:http://www.cnblogs.com/ccorz/p/Django-models-zhong-demeta-xuan-xiang.html

通过一个内嵌类 “class Meta” 给你的 model 定义元数据, 类似下面这样:

1
2
3
4
5
class Foo(models.Model):
bar = models.CharField(maxlength=30)
class Meta:
# ...

Model 元数据就是 “不是一个字段的任何数据” – 比如排序选项, admin 选项等等.

下面是所有可能用到的 Meta 选项. 没有一个选项是必需的. 是否添加 class Meta 到你的 model 完全是可选的.

  • verbose_name:verbose_name的意思很简单,就是给你的模型类起一个更可读的名字:
    1
    verbose_name = "pizza"

若未提供该选项, Django 则会用一个类名字的 munged 版本来代替: CamelCase becomes camel case.

  • verbose_name_plural:这个选项是指定,模型的复数形式是什么,比如:
    1
    verbose_name_plural = "stories"

若未提供该选项, Django 会使用 verbose_name + “s”.

我在项目中是这么使用的,举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Course(models.Model):
course_org = models.ForeignKey(CourseOrg, verbose_name="所属机构", null=True, blank=True)
# teacher = models.ForeignKey(Teacher, verbose_name="授课讲师", null=True, blank=True)
name = models.CharField(max_length=16, verbose_name="课程名")
description = models.CharField(max_length=32, verbose_name="课程简述")
detail = models.TextField(verbose_name="课程介绍")
degree = models.CharField(max_length=10, choices=(("easy","初级"), ("nomal","中级"), ("tough","高级")), default="easy", verbose_name="难度")
learning_time = models.IntegerField(default=0, verbose_name="课程时长(单位:分钟)")
learning_num = models.IntegerField(default=0, verbose_name="学习人数")
favor_num = models.IntegerField(default=0, verbose_name="收藏人数")
click_num = models.IntegerField(default=0, verbose_name="点击量")
image = models.ImageField(upload_to="course/%Y/%m", default="course/default.png", max_length=128, verbose_name="课程封面")
add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")
def __str__(self):
return self.name
class Meta:
verbose_name = "课程信息"
verbose_name_plural = verbose_name

一个很不错的博客:http://www.cnblogs.com/ccorz/,可以有时间看一下,带着质疑的态度去阅读。毕竟这是别人的理解,你自己的理解可能不是这样的,或者说他理解有问题。

回到老师的教学视频中。
定义字符集为utf-8,也就是#_coding:utf-8_,这个自己可以设置,而且在python3.X中比较少见这样的问题。

Navicat可以验证修改数据库是否修改成功了。其实就是一个数据库的可视化工具。

在数据库的表中,表的名称前面是应用的名称,后边是model将大写的形式全都转化成小写的形式的名称。

放张图:

models的讲解,老师讲的例子中用到的四个字段。Django给我们提供了大量的Field类型,其他的还有models.ForeignKey(), models.IntegerField,models.IPAddressField,models.FileField, models.ImageField等等。

我们可以点击models,找到field,看他的源码。有很多中的类型。

一些field类型的参数:等等
CharField必须制定最大的长度,还有一些可选的参数,比如null = True是表示是否可以为空,default是制定默认的值,在不对这个字段赋值的时候可以自动的赋值成默认值。blank = True是指的是值可以是一个空格。

一个数据库的表必须有主键,在项目中当我们不指定主键的时候,Django会自动生成一个ID,并且作为主键。当然我们也可以自己去定义主键,举个例子:

1
object_id = models.CharField(Primary_key = True, verbose_name = "主键")

使用makemigrations和migrate修改数据库。但是这时候会报错,说没有指定最大的长度,这里指的注意的一点就是CharField必须指定最大的长度,回去指定最大长度:

1
object_id = models.CharField(max_length = 128, Primary_key = True, verbose_name = "主键")

重新更新数据库发现还是报错,提示要指定一个默认值,回去再指定一个默认值:

1
object_id = models.CharField(max_length = 128, Primary_key = True, default = " ", verbose_name = "主键")

重新执行修改数据库的命令,发现成功了。

这时候可以看到我们把Django自动生成的那个id删掉了。

下面是Meta信息,比如db_table = ‘User_message’,这样在生成表的时候就生成这个名字的表。
还可以使用ordering来排序。

verbose_name_plural = verbose_name(或者直接用一个字符串给它赋值)


通过models查询数据库的内容。

假设我们在视图函数的文件里(views.py)添加下面的代码

1
from .models import ...

这里.代表的是和这个文件(views.py)在同一个文件夹下的models.py文件。

如何查询数据库中的记录。举个例子:

1
2
3
all_message = UserMessage.objects.all()
for message in all_message:
print message.name

pycharm可以设置断点。可以将操作习惯设置成和VS studio相同的。

objects还有一个函数叫filter(条件),来过滤得到的结果,只要留下符合条件的结果。

在给字段赋值中有中文的时候要在文件的最前面声明字符集,个人认为把数据库的字符集设置成utf-8就可以了,回去尝试一下。

验证一个值是否写入了数据库:

1
2
3
4
5
6
7
8
# 先实例化一个值
user_message = UserMessage()
# 然后每个字段的给它赋值
...
# 最后调用models的一个函数,因为我们继承于这个models.Model,所以我们也可以调用这个方法
user_message.save()

这样就存储了一组数据进了数据库的表中。

如何取出数据并且保存到数据库的中。

看.html文件,看form部分是怎样把数据传到后端并且保存到数据库中的。

前端的页面的文件中有input()函数,将参数传递到后台。

值得注意的一点是,

1
<form action = "/form/" method = "post" class = "smart-green">

form 前面和后面的斜杠一定要加上,不能忘。

Django不允许任意的form就像后台提交数据,这是我们要在前端代码里的


中加入一句
1
{% csrf_token %}

这样表单中的内容才能顺利的提交,这是Django的安全机制的问题。

刷新页面点击提交,数据就过去了。那是怎么过来的呢?

看request的这些参数中,POST是一个很重要的参数。我们在表单上点击提交之后发出的是一个post请求,所以在视图函数中要对收到的请求做类型的判断:

1
2
if request.method == "POST":
name = request.POST.get('name', '') # 这里的这个name必须是和POST中的name名称是一样的,否则就娶不到正确的数据了

在model中修改数据,包括增加和删除数据表中的数据。


在前端页面获取数据的时候,对于数据库中已经存在的数据,我们要把它显示到前端页面上。

1
2
3
message = None
if all_messages:
message = all_message[0]

在这里只取出了一条数据,希望把取出来的数据显示到前端页面中,有render方法

1
2
3
return render(request, 'message_form.html'{
"my_message":message
})

如何在前端页面中展示取出数据:

1
2
3
4
<label>
<span>邮箱</span>
<input id = "email" type = "email" values = "{{my_message.email}}" name =... >
</label>

django对html页面的代码里有逻辑的限制,不想PHP可以在html代码里嵌入大量的逻辑代码,那样的话维护起来就很麻烦。

如果我们想做if else等的用法,要使用Django提供的模板。这些逻辑里面是可以用双等号代表相等关系。怎样添加这些逻辑是之前Django的基础知识。

还有ifequal的用法。

我们如果想取有限的几个字段,Django给提供了slice函数。

比如Django的template一些内置的函数。

URL的配置技巧。在项目的urls.py文件中,修改:

1
url(r'^form/$', getform, name = 'go_form')

在html页面中,在action中,相当于起了一个别名。可以方便修改。

原来是:

1
<form action = "/form/" method = "post" class = "smart-green">

现在是:

1
<form action = "{% url 'go_form'%}" method = "post" class = "smart-green">

这样做的好处就是我们使用了一个别名来寻找form,及时前面的内容改动了,不至于整个项目相关的都做修改。

其实前面的那个form我也不知道代表的什么,晚上翻看下之前的视频,在这里写下答案。

还一个要注意的就是匹配URL地址的时候的正则表达式。/$表示要访问的是这个目录下的内容。

url括号里面前面的r’^form/$’

回顾下,就是从前端界面获得数据,存储到数据库中,然后再从models操作数据库,最后将数据库中的内容获取,显示到前端界面上。