想搞清楚Django跟后台数据库是如何交互的。在网上找了好多,不是太麻烦就是觉得不靠谱,对我都不适合,找了好久,最后看到一个自强学堂的网站,很喜欢里面的内容。照着教程搭了一遍,还剩一些bug没解决。我想先弄清楚django跟后台怎么交互的再说,先分着说,然后最后总结一下吧。
使用得环境是Centos7+python3+django1.8。
1 virtaulenv
官方解释:virtualenv是一个创建隔离的python环境的一个工具,额。。。按照我现在的理解我是粗略得把它理解成windows里面的虚拟机。每个虚拟机都是一个单独的环境,与别得虚拟机没有关系。如果后续有更深得理解,再更。
2 安装和使用virtualenv
pip install virtualenv virtualwrapper
编辑root用户家目录下的.bash_profile文件(如果不是root用户,并且需要使用sudo命令的话,应在sudo的配置文件中加上此用户),加上:
export WORKON_HOME=$HOME/.virtualenvs
source /usr/python3/bin/virtualenvwrapper.sh
wirtualwrapper.sh脚本文件会帮我们在.virtualenvs目录下创建虚拟环境必要的文件和目录,然后就可以使用啦。
我使用到的命令:
mkvirtualenv mic:创建mic项目和运行环境mic
当退出虚拟环境后还想再次运行,workon mic即可
注:这个地方写virtualenvwrapper.sh的路径即可。如果你的linux系统中同时装了python2和python3,那么要在这个脚本文件中声 明python3的路径,就像这样export VIRTUALENVWRAPPER_PYTHON=/usr/python3/bin/python3;
同时也要声明virtualenv在python3下的路径,就像这样
export VIRTUALENVWRAPPER_VIRTUALENV=/usr/python3/bin/virtualenv
3 数据库的模板和脚本文件(列出主要的)
以下脚本文件内容来自于自强学堂。
数据库的模板文件在$YOUAPP_PATH/models.py :
class Column(models.Model):
name = models.CharField('栏目名称', max_length=256)
slug = models.CharField('栏目网站', max_length=256, db_index=True)
intro = models.TextField('栏目介绍', default='')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('column', args=(self.slug, ))
class Meta:
verbose_name = '程序'
verbose_name_plural = '程序'
ordering = ['name']
class Article(models.Model):
column = models.ManyToManyField(Column, verbose_name='ofpro')
title = models.CharField('标题', max_length=256)
pub_date = models.DateTimeField('发表时间', auto_now_add=True, editable=True)
update_time = models.DateTimeField('更新时间', auto_now=True, null=True)
slug = models.CharField('网站', max_length=256, db_index=True)
author = models.ForeignKey('auth.User', blank=True, null=True, verbose_name='作者')
published = models.BooleanField('最后发布', default=True)
content = UEditorField('内容', height=300, width=1000, default=u'', blank=True, imagePath='uploads/images/',toolbars='besttome', filePath='uploads/files/')
# UEditor是google的编辑器, 还没研究具体怎么用
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article', args=(self.slug, ))
# reverse函数获取路径,在前端页面中调用get_absolute_url跳转到这个页面
class Meta:
verbose_name = '教程'
verbose_name_plural = '教程'
数据库脚本文件 :
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2015-07-28 20:38:38
# @Author : Weizhong Tu (mail@tuweizhong.com)
# @Link : http://www.tuweizhong.com
'''
create some records for demo database
'''
from minicms.wsgi import *
from news.models import Column, Article
def main():
columns_urls = [
('体育新闻', 'sports'),
('社会新闻', 'society'),
('科技新闻', 'tech'),
]
for column_name, url in columns_urls:
c = Column.objects.get_or_create(name=column_name, slug=url)[0]
# 创建 10 篇新闻
for i in range(1, 11):
article = Article.objects.get_or_create(
title='{}_{}'.format(column_name, i),
slug='article_{}'.format(i),
content='新闻详细内容: {} {}'.format(column_name, i)
)[0]
article.column.add(c)
if __name__ == '__main__':
main()
print("Done!")
urls.py文件(部分) :
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^ueditor/', include(DjangoUeditor_urls)),
url(r'^$', 'news.views.index', name='index'),
# name是正则表达式的别名,在.html文件中使用这个>匹配条件时,
# 只用写上index,即使正则表达式匹配规则更改也没>关系。
url(r'^column/(?P<awm>[^/]+)/$', 'news.views.column_detail', name='column'),
# ?P<awm>这个awm相当于一个变量,[^/]不匹配/,+匹配前面的正则一次或多次,
# http://192.168.80.126:8080/column/tech/a/ : tech就是这个awm变量的值,
# 由于后面有不匹配tech后的/, 因此后面的a参数不被匹配,就报错.
# 这个变量是在views中传递给函数的,因此在返回给 户端后,可以在页面打印出来.
url(r'^news/(?P<article_slug>[^/]+)/$', 'news.views.article_detail', name='article'),
]
views.py文件 :
from django.shortcuts import render
from django.http import HttpResponse
from .models import Column, Article
def index(request):
columns = Column.objects.all()
return render(request, 'index.html', {'columns': columns})
# awm参数是从urls中传递过来的
def column_detail(request, awm):
column= Column.objects.get(slug=awm)
return render(request, 'news/column.html', {'column': column})
def article_detail(request, article_slug):
# article = Article.objects.get(slug=article_slug)[0]
article = Article.objects.filter(slug=article_slug)[0]
return render(request, 'news/article.html', {'article': article})
index模板文件 :
{% extends "base.html" %}
{% block title %} 首页 {% endblock title %}
{% block content %}
<ul>
{% for column in columns %}
<li>
<a href="{{ column.get_absolute_url }}">{{ column.name }}</a>
</li>
{% endfor %}
</ul>
{% endblock content %}
column模板文件 :
{% extends "base.html" %}
{% block title %}
{{ column.title }}
{% endblock title %}
{% block content %}
<p>栏目名称: {{ column.name }}</p>
栏目简介: {{ column.intro }}
栏目文章列表:
<ul>
{% for article in column.article_set.all %}
<li>
<a href="{{ article.get_absolute_url }}">
{{ article.title }}
</a>
</li>
{% endfor %}
</ul>
{% endblock content %}
article模板文件 :
{% extends "base.html" %}
{% block title %}
{{ article.title }}
{% endblock title %}
{% block content %}
<h1>文章标题: {{ article.title }}</h1>
<div id="main">
{{ article.content }}
</div>
{% endblock content %}
分析:
启动django后,当我输入http://IP:PORT时, 会进入url控制器, 显然http://IP:PORT符合url中的
url(r'^$', 'news.views.index', name='index')这条规则, 此时django会去news(app名)下的views(视图)文件中的index函数。
下面的代码是视图中的index函数的部分 :
def index(request):
columns = Column.objects.all()
return render(request, 'index.html', {'columns': columns})
不清楚Column.objects.all()的值 :
打开python3 manage.py shell
>>> from .models import Column, Article
>>> columns = Column.objests.all()
>>> columns
[<Column: 体育新闻>, <Column: 社会新闻>, <Column: 科技新闻>]
index函数返回被渲染后的index.html文件, 然后就是打开网页看到的内容 :
index.html文件部分内容 :
{% for column in columns %}
<li>
<a href="{{ column.get_absolute_url }}">{{ column.name }}</a>
</li>
{% endfor %}
网页显示column.name,column.name是之前插入的column_name, 也就是体育新闻,社会新闻,科技新闻三个字段.
数据库脚本文件部分
columns_urls = [
('体育新闻', 'sports'),
('社会新闻', 'society'),
('科技新闻', 'tech'),
]
for column_name, url in columns_urls:
c = Column.objects.get_or_create(name=column_name, slug=url)[0]
然后在index.html文件中可以看到, 这三个字段分别连接到get_absolute_url这个函数的返回值中, 于是去models.py文件中(模型)中找到这个函数:
def get_absolute_url(self):
return reverse('column', args=(self.slug, ))
这个返回值是/column/SLUG, 这里的SLUG也就是前面数据库脚本文件中的url变量的值, 由数据库脚本看出体育新闻对应的SLUG是sports, 社会新闻对应的SLUG是soceity, 科技新闻对应的SLUG是tech, 即当我点击体育新闻时, 会请求/column/sports页面. 这一步完成了前端到后台数据库取数的步骤. url控制器会查看url模式, 发现匹配 :
url(r'^column/(?P<awm>[^/]+)/$', 'news.views.column_detail', name='column'),
于是去视图中找column_detail函数:
def column_detail(request, awm):
column= Column.objects.get(slug=awm)
return render(request, 'news/column.html', {'column': column}
于是找到模板目录的news下的column.html :
<p>栏目名称: {{ column.name }}</p>
栏目简介: {{ column.intro }}
栏目文章列表:
<ul>
{% for article in column.article_set.all %}
<li>
<a href="{{ article.get_absolute_url }}">
{{ article.title }}
</a>
</li>
{% endfor %}
</ul>
页面内容 :
不是很清楚column.article_set.all和 article.title的值,打开shell, 可以看到column.article_set.all的值 :
>>> from news.models import Article, Column
>>> column = Column.objects.get(slug='sports')
>>> column
<Column: 体育新闻>
>>> column.article_set.all
<bound method BaseManager.all of <django.db.models.fields.related.create_many_related_manager.<locals>.ManyRelatedManager object at 0x7f91b517db38>>
>>> column.article_set.all()[<Article: 体育新闻_1>, <Article: 体育新闻_2>, <Article: 体育新闻_3>, <Article: 体育新闻_4>, <Article: 体育新闻_5>, <Article: 体育新闻_6>, <Article: 体育新闻_7>, <Article: 体育新闻_8>, <Article: 体育新闻_9>, <Article: 体育新闻_10>, <Article: 体育新闻_1>, <Article: 体育新闻_2>, <Article: 体育新闻_3>, <Article: 体育新闻_4>, <Article: 体育新闻_5>, <Article: 体育新闻_6>, <Article: 体育新闻_7>, <Article: 体育新闻_8>, <Article: 体育新闻_9>, <Article: 体育新闻_10>, '...(remaining elements truncated)...']
>>> column.article_set.all()[0].title
'体育新闻_1'
也就是上图中看到的体育新闻1-10.
总结: django大致的工作流程是: 当有请求到达时, 先去url控制器查找匹配规则, 匹配成功去view视图中找到相应的方法(函数), 然后去对应的模板目录找到html文件, 在html中获取models(模型)中相应的变量值, 然后将结果返回给客户端. 数据库脚本文件中涉及到数据库表的多对多关系, 没有做说明, 文中一些bug也没说明.