跟着Django手册建立Blog(一)
来源:互联网 发布:仿手机淘宝 html5 编辑:程序博客网 时间:2024/05/02 05:01
环境: python 3.4, Django 1.11.1, pycharm2016.3
教材: Django document 1.11.2,Django 1.10翻译中文版
目标:建立一个polls(投票)的网页app.
教材: Django document 1.11.2,Django 1.10翻译中文版
目标:建立一个polls(投票)的网页app.
步骤:
1. 建立mysite project
利用virtualenvwrapper建立''blogpy34'' 虚拟环境(代表编译器是python3.4), 在pycharm中建立mysite project, 过程省略.
2. pycharm中新建polls app
a. pycharm菜单Tools--Run Manage.py Task
b. 在pycharm下方的命令行中输入startapp polls
c. 编辑polls app中views代码
from django.shortcuts import renderfrom django.http import HttpResponsedef index(request): # 每一个def定义了根据request请求而返回的HttpResponse响应. return HttpResponse("Hello,world. You're at the polls index.")d. 新建并编辑polls app中urls
from django.conf.urls import urlfrom . import viewsurlpatterns = [ url(r'^$', views.index, name = 'index'),] # 正则表达式匹配浏览器输入的url, 匹配上的就返回views中index响应.e. 配置root urls, 关联app中urls
在第一条url后面插入第二条url: url(r'^polls/', include('polls.urls')),
3. 设置数据库
a. 设置数据库引擎
在settings中DATABASES中设定后端引擎为sqlite3(自己选择).
b. pycharm命令行中执行migrate
settings中installed app在执行时需要使用数据库中的表, 为了它们能正常运行, 需要为它们建立数据库中的表.
project目录下的db.sqlite3将发生变化, 根据installed app来创建表格
4. 新建Models
a. 为poll app创建Question和Choice model
在polls app下的models中输入如下代码:
from django.db import modelsclass Question(models.Model): question_test = models.CharField(max_length=200) # "question_test"将会成为数据表中的列名. pub_date = models.DateTimeField('date published') # 因有对pub_date重新命名, 数据表中列名是'date published'class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)
5.激活Models
a. installed apps注册自己的app在settings中的installed apps中增加一条: polls.apps.PollsConfig
b. 输入makemigrations polls
在pycharm命令行中输入makemigrations polls, 在polls migrations下增加一个0001.initial.py
c. 输入sqlmigrate polls 0001
命令行中将出现以下动作:
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_test" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id"));
INSERT INTO "polls_choice" ("question_id", "votes", "choice_text", "id") SELECT NULL, "votes", "choice_text", "id" FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
Process finished with exit code 0
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_test" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id"));
INSERT INTO "polls_choice" ("question_id", "votes", "choice_text", "id") SELECT NULL, "votes", "choice_text", "id" FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
Process finished with exit code 0
d. 输入migrate
输入前, 数据库状态
输入后, 数据库状态:
db下增加2个表格, polls_choice和polls_question, 在django_migrations表格中新增一条polls 0001的记录, 如果该表格中已存在polls 0001, django检查到后将不新建choice和question表格.
重温变更models的三部曲:
① 在models.py中变更models
②运行makemigrations为那些变更生成migrations, migrations可视为migrate的对象.
③运行migrate, 将那些变更migrate到数据库中.
6. 探索数据库 API
a. 在manage.py的命令行中输入shell, 则进入python交互环境.
b. 输入如下代码:
>>>from polls.models import Question, Choice>>>Question.objects.all()<QuerySet []>>>>from django.utils import timezone>>>q = Question(question_text="What's new?", pub_date=timezone.now())>>>q.save()>>>q.id1>>>q.question_text"What's new?">>>q.pub_datedatetime.datetime(2017, 6, 5, 14, 21, 50, 920284, tzinfo=<UTC>)>>>q.question_text = "What's up?">>>q.save()>>>Question.objects.all()<QuerySet [<Question: Question object>]>最后一句中的<Question: Question object>不能很好的表明该对象身份, 为了改善, 需要在Question models中为Question和Choice类增加__str__()方法.
class Question(models.Model): ...... def __str__(self): return self.question_text def was_published_recently(self): # 该方法只是用来演示, 这只是普通的python方法. return self.pub_date >= timezone.now() - datetime.timedelta(days=1)class Choice(models.Model): ...... def __str__(self): return self.choice_text继续探索数据库API
>>> from polls.models import Question, Choice
# 确认下__str__()是否生效>>> Question.objects.all()<QuerySet [<Question: What's up?>]>
# Django提供了丰富的数据库API, 完全以keyword参数驱动.>>> Question.objects.filter(id=1)<QuerySet [<Question: What's up?>]>>>> Question.objects.filter(question_text__startswith='What')<QuerySet [<Question: What's up?>]>
# 获得今年发布的问题>>> from django.utils import timezone>>> current_year = timezone.now().year>>> Question.objects.get(pub_date__year=current_year)<Question: What's up?>
#请求一个不存在的ID, 会引发报错.>>> Question.objects.get(id=2)Traceback (most recent call last):......polls.models.DoesNotExist: Question matching query does not exist.
# 查找某个主键>>> Question.objects.get(pk=1)<Question: What's up?>
# 验证下自定义的was_published_recently方法是否生效>>> q = Question.objects.get(pk=1)>>> q.was_published_recently()True
# 为某个问题建立好几个选项, Django会用一个集合装载外键关系的另外一侧, 如Question' choice>>> q = Question.objects.get(pk=1)>>> q.choice_set.all()<QuerySet []> # 目前主键为1的问题下面, 没有任何选项.# 为问题建立选项>>> q.choice_set.create(choice_text='Not much', votes=0)<Choice: Not much>>>> q.choice_set.create(choice_text='The sky', votes=0)<Choice: The sky>>>> q.choice_set.create(choice_text='Just hacking again', votes=0)<Choice: Just hacking again>>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)# choice可以回溯它的问题.>>> c.question<Question: What's up?>>>> q.choice_set.all()<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>, <Choice: Just hacking again>]>>>> q.choice_set.count()4>>> Choice.objects.filter(question__pub_date__year=current_year)<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>, <Choice: Just hacking again>]>>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')>>> c.delete()(2, {'polls.Choice': 2})
7.引入Django Admin
a. 创建superuser
manage.py@mysite > createsuperuser然后按提示输入用户名, 邮箱, 密码.
b. 开启开发服务器
manage.py@mysite > runserver
c. 浏览器输入"http://127.0.0.1:8000/admin/"
输入账号密码后看到界面:
看到的Groups和Users是由django.contrib.auth生成的.
8. 让polls app在admin中可修改.
此时在admin中看不到我们建立的polls app, 要显示的话, 需要告诉admin, Question对象在admin中是有界面的.
a. 修改polls admin
from django.contrib import adminfrom .models import Question# Register your models here.admin.site.register(Question)b. 在浏览器检查效果
c. 进入Question修改页面
d. 点击其中一个Question修改页面
可以看到, 字符类型的Question text与日期类型的Date published, 可以自动的以合适的方式显示. 在此页面可以对键进行修改, 修改之后按保存, 保存之后按History就能看到修改履历.
9. 创建views
网站的每个页面是由一个个views生成的, views是函数或者类的方法.
现在为polls app添置更多的views: detail, result, vote.
a. 在polls/views.py中键入代码
def detail(request, question_id): return HttpResponse("You're looking at question %s." % question_id)def results(request, question_id): response = "You're looking at the results of question %s." return HttpResponse(response % question_id)def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id)
urlpatterns = [ url(r'^$', views.index, name = 'index'), url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'), url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'), url(r'^(?P<question_id>[0-9]+)/vote$', views.vote, name='vote'),]
浏览器中输入网址/polls/12,, 验证.
当输入网址后, Django会加载mysite.urls Python模块, 因为在mysite.setting中已经指定了.
Django根据mysite.urls中的正则表达式, 一条条进行匹配, 匹配OK了就转入相应的views, 相应的views则返回HttpResponse.
10. 写一写"会做事"的views
a. 在polls/views.py中改写以下代码, 其余代码不动.
from .models import Questiondef index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output)这里有一个问题, 这一页面的设计是写死在view中的, 如果想改变页面的外观, 则必须重新编辑这部分代码. 更好的方式是利用django的template system来分离页面设计的代码到template中.
b. 在polls下创建template目录.
c. 在刚创建的template目录下创建polls目录.
d. 在刚创建的polls目录下创建index.html文件.
为何要新建一个polls文件夹, 然后把index放在里面?
因为Django没有办法区分不同app里面同样名字的template, 比如polls里面的index和polls2里面的index. 最简单的解决方式是如上面3步, 把index放在template文件夹下的polls文件夹下, 这样django就知道这个index是属于polls这个app的.
e. 修改index template
在index中输入以下代码
{% if latest_question_list %} # 判断views那边传过来的latest_question_list元组是否为空. <ul> # unorder list, 不带编号的列表. {% for question in latest_question_list %} # 将元组中的问题循环取出. <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> # 取出的每个问题都包装成链接polls/{{question.id}},加{{}}的目的是为了将其"变成一个变量"(不严谨说法) {% endfor %} </ul> {% else %} <p>No polls are available.</p>{% endif %}
如果忘记了question object下面有哪些键, 打开db数据库查看question表就知道了.
from django.template import loaderdef index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') # 加载polls/index.html这个template context = { 'latest_question_list': latest_question_list, # 将latest_question_list这个元组包装成字典context. } return HttpResponse(template.render(context, request)) # 将字典context使用index模板进行渲染.这样在浏览器输入http://127.0.0.1:8000/polls/, 能看到question
可以看到question有链接, 这是因为在index template中设置了链接, 链接显示的文字就是question.question_text.
<a href="/polls/{{ question.id }}/">{{ question.question_text }}点击链接后, urls模块识别出/polls/1/之后, 指向views.detail, 生成以下页面:
g. 使用shortcut的render()
上面的代码需要调用HttpResponse, Loader模块, 语句繁琐, 更简洁的方法是调用shortcut的render().
from django.shortcuts import renderfrom django.http import HttpResponse #没用了from .models import Questionfrom django.template import loader #没用了def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] #template = loader.get_template('polls/index.html') # 引入shortcut的render之后, 不需要写那么多 context = { 'latest_question_list': latest_question_list, } #return HttpResponse(template.render(context, request)) # 引入shortcut的render之后, 不需要写那么多 return render(request, 'polls/index.html',context)
11. 弹出404错误.
a. 修改polls/views中的detail
from django.http import Http404def detail(request, question_id): try: question = Question.objects.get(pk=question_id) except Question.DoesNotExist: raise Http404("Question does not exist.") return render(request, 'polls/detail.html', {'question': question})b. 创建detail template
在templates-polls下建立detail.html, 写入{{ question }}.
c. 快捷方式: get_object_or_404()
因为使用get()方法而找不到相应对象时弹出Http404是常用的用法, django提供了快捷方式, 下面重写detail.
12. 使用template系统
a.重写detail.html template
<h1>{{ question.question_text }}</h1> # template系统采用一种dot-lookup语法来获得变量参数.首先在对象question中寻找,失败后在question的参数中寻找.<ul> {% for choice in question.choice_set.all %} #被理解成python代码"question.choice_set.all()", 即一个可迭代对象. <li>{{ choice.choice_text }}</li> {% endfor %}</ul>
13. 去除template中URL的硬编码(死写法)
a. 将死写法变成活写法
在polls/index.html模板中, 链接的'/polls/'是硬编码
<a href="/polls/{{ question.id }}/">{{ question.question_text }}</a>进行改写
<a href="{% url 'detail' question.id %}">{{ question.question_text }}</a>程序将从polls/urls.py中寻找名称为'detail'的url pattern进行url匹配.
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),当你想把url改为其他形式, 比如polls/list/1/的时候, 只需要在urls中更改, 不需要在template中更改, 实现了urls与template模块的弱耦合.
b. URL名称的命名空间
上面的URL名称是''detail'', 在当前只有一个app情况下不会造成混淆, 当有多个app时, 有可能在别的app中也有另外一个''detail'', 造成混淆.
a. 在polls/urls.py中指定app名字
from django.conf.urls import urlfrom . import viewsapp_name = 'polls' #指定app名字urlpatterns = [ url(r'^$', views.index, name = 'index'), url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'), url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),]b. 修改polls/templates/polls/index.html
将其中'detail'变成'polls:detail'
<a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a>
阅读全文
0 0
- 跟着Django手册建立Blog(一)
- 跟着Django手册建立Blog(二)
- 跟着Django手册建立Blog(三)--引入自动测试
- 跟着Django手册建立了Blog(四)--写静态文件
- Django-blog-zinnia初体验(一)
- Django(2)--window环境一分钟建立Django项目
- Django 手册
- django手册
- Django&&blog
- Django blog
- Django blog
- Django blog
- Django blog
- Django blog
- Django blog
- Django blog
- 跟着开发手册学习php
- blog建立!
- lubuntu自动登录(lxde)
- JDBC自定义框架
- 验证身份证的有效性
- 关于QT中的工程文件.pro的介绍
- GitHub完美适配Visual Studio-04 团队协作
- 跟着Django手册建立Blog(一)
- [LeetCode] Regular Expression Matching
- 一些资料
- IOS端K线系列之K线-整体搭建
- 东方快车谋杀案
- 我不认识的英语单词
- 编译过程,make,makefile,cmake,qmake,cmakelist总结
- 制作文件系统
- 解决问题:zipimport.ZipImportError: can't decompress data; zlib not available