对 django 官网 First steps 中 7 个入门教程的复习,复习时 django 版本为 1.11。
tutorial01
1、每一个新建的 app 都应再新建一个 urls.py
文件, 管理其目录下的 views.py,在 mysite/urls.py
文件中使用 include()
方法引用 app 里的 urls;
2、urls.py
文件里的 url()
方法可以传四个参数,两个为必须,两个可选:
四个参数 | |
---|---|
url() argument:regex | 正则表达式(必须) |
url() argument:view | views.py 中的方法(必须) |
url() argument:kwargs | 可以传入views.py 中的方法的字典(可选) |
url() argument:name | 用于给 html 页面的链接命名(可选) |
tutorial02
1、models.py
可以定义任何数据模型,模型之中可以定义自己的方法或者官方自带的方法,在用此模型的时候可以调用这些添加的方法,方面理解:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self): # 自带方法
return self.question_text
def was_published_recently(self): # 自定义方法
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
2、每次修改 models.py
里的数据模型,需要运行两个命令:
python manage.py makemigrations polls
迁移改变
python manage.py migrate
应用到数据库
其他命令:
python manage.py sqlmigrate polls 0001
查看此次迁移 sql 语法python manage.py shell
在命令行里调试数据模型
tutorial03
1、在 urls.py
中,url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail')
,其中用括号括器的(?P<question_id>[0-9]+)
会做为参数传给 views.detail
这个函数,这个函数也要接受这个参数做下一步处理,可以去掉?P<question_id>
,这只是为了起说明作用和提前命名,也可以在 views.detail
方法中命名;
2、views.py
中,用get_object_or_404()
函数代替try···except
更好,在找不到相关数据时 Django 会自动引起 Http404
错误:
# 用 try···except 查询数据
def 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})
# 用 get_object_or_404() 查询数据
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
3、模板中使用 url,尽量不要硬编码,<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
这样的硬编码在改动 urls.py
会很费劲,正确方法是用命名空间,在多个 app 中,可能出现很多同名的 name,这很难记忆,为每一个 app 设置一个 app_name
,在搭配url(r'^$', views.index, name='index')
中的name
,即可在改变 url 路径时不必一改全改,也方便记忆和使用:
# app/urls.py
app_name = 'polls' # 在每一个 app 的 urls.py 下设置
urlpatterns = [
url(r'^$', views.index, name='index'),
]
# templates/name.html
<!-- 硬编码方式 -->
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
<!-- 更好的编码方式 -->
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
tutorial04
1、表单提交,如某项数据需要+1,多人同时提交时,可能会出现数据丢失,通常的代码将这个值从数据库取出来赋值给一个变量,然后执行+1操作,然后再将这个+1后的值保存会数据库,这就可能会出现数据遗漏
,更有效的做法是使用 F()
函数,这个函数对数据库直接进行+1操作
,而不用通过变量赋值存储:
# 有可能会出现数据遗漏的代码操作,有 Question和Choice 模型
selected_choice = question.choice_set.get(pk=request.POST['choice'])
selected_choice.votes += 1
selected_choice.save()
# 更有效的数据+1操作方法,使用 F() 函数
Choice.objects.filter(votes='hello').update(votes=F('votes')+1)
2、类的通用视图,Less code is better。在 views.py
中,初学 django 时直接用了很多函数来处理每个模板和数据,这种方法也可行,但 django 提供了通用视图使代码更简洁更友好;
# urls.py 通用视图默认变量为pk,所以使用pk
from django.views.generic import TemplateView
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
url(r'^about/$', TemplateView.as_view(template_name="about.html")),# 没有数据查询时可以直接返回模板,这是一种简写方式
]
# views.py
def index(): # 普通函数,与通用视图对比
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {
'latest_question_list': latest_question_list,
}
return render(request, 'polls/index.html', context)
class IndexView(generic.ListView): #通用视图
template_name = 'polls/index.html' #指定渲染的模板
context_object_name = 'latest_question_list' #模板中的变量名,类似 context 上下文
def get_queryset(self): # 重写 ListView 方法,查询数据
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):# DetailView
model = Question # 指定要查询的数据模型
template_name = 'polls/detail.html' # 指定渲染模板
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html
通用视图除了可以查询指定模型、渲染指定模板外(像上面那样,使用指定参数),还可以添加额外的上下文
(也就是context
),只需重写 get_context_data()
方法:
class PublisherDetail(DetailView):
model = Publisher
def get_context_data(self, **kwargs):
context = super(PublisherDetail, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
常用字段解释 | |
---|---|
context_object_name | 指定模板内的变量名,默认为 object_list |
model | 要查询的模型名称 (简写) |
query | 是上面的完全写法 ,不一定是 all(),也可以是其他,filter() 等 |
template_name | 指定渲染哪一个模板 |
常用方法解释 | |
---|---|
get_queryset(self) | 模型查询处理 |
get_context_data(self, **kwargs) | 添加额外上下文 |
tutorial05
1、自动化测试可以发现工程中隐藏的 bug,可以优化代码、保证项目的安全。在每个 app 下都有一个 tests.py
文件用来测试所在 app 是否有 bug,测试方法以 test 开头
,类以 Tests 结尾
:
# app/tests.py
import datetime
from django.test import TestCase # 用于测试的工具
from django.urls import reverse
from django.utils import timezone
from .models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'no polls are available')
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_past_question(self):
create_question(question_text='Past question.', days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
断言介绍 | |
---|---|
assertIs | 判断真假 |
assertEqual | 判断是否相等 |
assertContains | 内容是否包含在内 |
assertQuerysetEqual | Queryset是否相等 |
tutorial06
1、添加静态文件支持,根目录下新建 static
文件夹管理 css、js、image
资源,在 settings.py
文件中设置 STATIC_URL
和 STATICFILES_DIRS
,django 会自动搜寻 INSTALLED_APPS
下的 app 并找到 static
文件夹:
# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
编写 css
文件:
/* style.css */
li a {
color: green;
}
body {
background: white url("images/background.gif") no-repeat right bottom;
}
在 html
中引用:
{# index.html #}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
tutorial07
1、后台管理优化,可以在后台帮助数据模型显示详情信息:
字段解释 | ||
---|---|---|
fields | fields = ['pub_date', 'question_text'] | 设置模型中字段的顺序及是否显示 |
fieldsets | fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date']}), ] | 将模型中的每个字段分栏 |
inlines | inlines = [ChoiceInline] | 将有关联的模型引入,可直接操作该引入模型 |
list_display | list_display = ('question_text', 'pub_date') | 模型列表详情 |
search_fields | search_fields = ['question_text'] | 添加后台对指定字段的搜索功能 |