django tutorial 都说了什么。

新建项目及应用

安装虚拟环境和django

pip install virtualenv

新建虚拟环境并安装django

# 安装依赖python3 的虚拟环境
virtualenv djangovenv -p python3

workon djangovenv
# 安装django
pip install django

新建项目和应用

# 新建项目
django-admin startproject mysite
cd mysite
# 新建应用
python manage.py polls

路由映射

路由映射到基于函数的视图---FBV

  • mysite/urls.py
from django.urls import path, include

urlpatterns = [
  path('polls/', include('polls.apps.PollsConfig'), name='polls')
]
  • polls/urls.py
from django.urls import path
from . import views

app_name='polls'
urlpatterns =[
  # 基于函数的视图函数映射
  path('', views.index, name='index'),
  path('<int:question_id>/', views.detail, name='detail'),
  path('<int:question_id>/results/', views.results, name='results'),
  path('<int:question_id>/vote/', views.vote, name='vote'),
]

视图映射到基于类的视图---CBV

from django.urls import path
from .import views

app_name='polls'
urlpatterns=[
  path('', views.IndexView.as_view(), name='index'),
  # 通过视图类渲染的, id直接命名pk
  path('<int:pk>/', views.DetailView.as_view(), name='detail'),
  path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
  # vote没有视图模板, 所以不需要视图类
  path('<int:question_id>/vote/', views.vote, name='vote'),
  

视图函数

基于函数的视图

  • polls/views.py 三种方法渲染视图模板
from django.shortcuts import render, get_object_or_404
from django.url import request, HttpResponse
from django.template import loader

def index(request):
    latest_question_list = Question.objects.order_by('-pub_time')[:5]
    # 1. 直接文字显示结果
    # output = ','.join([q.question_text for q in latest_question])
    # return HttpResponse(output)

    context = {
        'latest_question_list': latest_question_list
    }
    ## 2. 通过loader.template
    template = loader.template('polls/index.html')
    return HttpResponse(template.render(context, request))
    
    ## 3. 通过render函数渲染模板
    return render(request, 'polls/index.html, context)

基于类的视图

Django封装了不同类型的视图类, 只需要填写对应的属性或改写响应的方法就能自动渲染响应模板

  • views.py
from django.views import generic

def IndexView(generic.ListView):
  model = Question
  context_object_name='latest_question_list'
  template_name='polls/index.html'

  def get_queryset(self):
    return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]

def DetailView(generic.DetailView):
  model = Question
  template_name='polls/detail.py'

  def get_queryset(self):
    # 过滤未来发布问题, 再测试中纠正的错误
    return Question.objects.filter(pub_date__lte=timezone.now()

def ResultsView(generic.DetailView):
  model = Question
  template_name='polls/results.py'

路由映射到类函数

数据库模型

新建数据库类

  • models.py
from django.db import models
from django.utils import timezone

class Question(models.Model):
  question_text = models.CharField(max_length=200)
  pub_date = models.DatetimeField(default=timezone.now())

  def __str__(self):
    return self.question_text

  def was_published_recently(self):
    # 一天内发布的问题为近期问题, 注意未来的时间点不是近期,需要做分割
    return self.pub_date-datetime.delta(days=1) <= self.pub_date <= timezone.now()

class Choice(models.Model):
  question = models.ForeignKey(Question, on_delete=models.CASCADE)
  choice_text = models.CharField(max_length=200)
  vote = models.IntegerField(default=0)

  def __str__(self):
    return self.choice_text
  • setting.py 中添加应用配置
INSTALLED_APP=[
  'polls.apps.PollsConfig',
  ...
]
  • 命令行生成数据库

# 生成迁移文件
python manage.py makemigrations polls
# 执行迁移
python manage.py migrate
# 执行指定迁移
python manage.py migrate polls 0001

交互窗口操作数据库

python manage.py shell
>>> from .models import Question, Choice
>>> from django.utils import timezone
>>> Question.objects.create(question_text='What's up?', pub_date=timezone.now())
>>> q = question.objects.get(pk=1)
>>> q.question_text
>>> q.pub_date
>>> q.id
>>> q1 = Question(question_text='What's your favorate color?', pub_date=timezone.now())
>>> q1.save()
>>> Question.objects.all()
>>> q.choice_set.all()
>>> >>> 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>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
>>> c.question
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

视图函数与模板

编写测试

  • TestCase类

对数据库模型类的实例方法的测试

通过执行结果与期待的结果相同,则测试通过

import datetime
from django.test import TestCase
from django.utils import timezone
from .model import Question, Choice

class QuestionTestCase(TestCase):
  """Question 模型单元测试"""
  def test_was_published_recently_with_future_question(self):
    # 测试未来的任务, 是否是最近的任务, 期待结果是False
    future_question = Question(pub_date=timezone.now()+datetime.timedelta(days=30))
    self.assertIs(future_question.was_published_recently, False)

  def test_was_published_recently_with_order_question(self):
    # 测试过去的任务(一天以上), 是否是最近的, 期待结果是False
    order_question = Question(pub_date=timezone.now()-datetime.timedelta(days=30))
    self.assertIs(order_question.was_published_recently, False)

  def test_was_published_recently_with_recently_quesiton(self):
    # 测试一天内的任务是否为最近任务, 期待结果为True
    recently_question = Question(pub_date=timezone.now()-datetime.timedelta(hours=23,minutes=59,seconds=59)
    self.assertIs(recently_question.was_published_recently, True)
  ## 通过以上的三个测试通过,对应选项, 可以判定哪个区间出了问题, 来修补漏洞

对视图函数测试响应结果数据

def create_question(question_text, days):
  # 与之前的创建实例不同, 这个需要写入测试临时数据库中
  time = timezone.now() + datetime.timedelta(days=days)
  return Question.objects.create(question_text=question_text, pub_date=pub_date)

class QuestionIndexViewTestCase(TestCase):
   def test_no_question(self):
    # 测试没有发布问题 期待 访问成功, 响应包含为 "No Polls.." queryset为[]
    response = self.client.get(reverse('polls:index'))
    self.assertEqual(response.status_code, 200) # 测试访问状态码, 连接成功
    self.assertContains(response, 'No polls')
    self.assertQuerysetEqual(response.context['latest_question_list'], [])

  def test_past_question(self):
    # 测试过去发布问题, 期待queryset中包含[question]
    question = create_quesiton("Past question", days=-30)
    response = self.client.get(reverse('polls:index'))
    self.assertQuerysetEqual(response.context['latest_question_list'], [question])

  def test_future_question(self):
    # 测试未来时间发布问题, 期待queryset为[]
    question = create_quesiton("Future question", days=30)
    response = self.client.get(reverse('polls:index'))
    self.assertQuerysetEqual(response.context['latest_question_list'], [])

  def test_past_question_and_future_question(self):
    # 测试过去发布问题, 期待queryset中包含[question]
    question = create_question("Past question", days=-30)
    create_question("Future question", days=30)
    response = self.client.get(reverse('polls:index'))
    self.assertQuerysetEqual(response.context['latest_question_list'], [question])

  def test_two_past_questions(self):
    # 测试过去发布问题, 期待queryset中包含[question1, question2]
    question1 = create_quesiton("Past question 1.", days=-30)
    question2 = create_quesiton("Past question 2.", days=-5)
    response = self.client.get(reverse('polls:index'))
    self.assertQuerysetEqual(response.context['latest_question_list'], [question2, question1])


class QuestionDetailViewTestCase(TestCase):
    # 测试过去发布问题, 期待结果中包含对应问题
    def test_past_question(self):
        question = create_question(question_text="Past question", days=-5)
        response = self.client.get(reverse('polls:detail', args=(question.id,)))
        self.assertContains(response, question.question_text)
    # 测试未来发布问题, 期待结果访问结果未找到 404
    def test_future_question(self):
        question = create_question(question_text="Future question", days=5)
        response = self.client.get(reverse('polls:detail', args=(question.id,)))
        self.assertEqual(response.status_code, 404)

后台模板渲染

posted @ 2022-03-26 23:58  lghgo  阅读(39)  评论(0编辑  收藏  举报