Django入門-從0開始編寫一個投票網(wǎng)站(三)

接上一篇Django入門-從0開始編寫一個投票網(wǎng)站(二)
開始筆記的part5-6疏虫。

part 5

  • 第一個自動化測試
    我們之前加的Question.was_published_recently()有一個bug:如果日期是在未來,返回的也是True。要驗(yàn)證這個导俘,可以通過shell來創(chuàng)建一個quesiton榄审,日期是未來的某一天,然后驗(yàn)證:
    >>> import datetime
    >>> from django.utils import timezone
    >>> from polls.models import Question
    >>> future_question = Question(pub_date=timezone.now() + date time.timedelta(days=10))
    >>> future_question.was_published_recently()
    
    噼里啪啦一頓下來返回True贩虾,顯然有問題催烘。

  • 創(chuàng)建一個test來暴露bug,test的方法寫在tests.py里缎罢。
    import datetime
    from django.utils import timezone
    from django.test import TestCase
    from .models import Question
    class QuestionMethodTests(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)
    
    我們這里創(chuàng)建了一個django.test.TestCase的子類颗圣,定義了方法(方法一定要以test開頭)。這個方法里創(chuàng)建了一個未來日期的Question屁使,我們通過斷言來判斷它的was_published_recently()是否是期望的False在岂。

  • 跑測試。在終端運(yùn)行:
    python manage.py test polls
    
    然后看到
    test_polls_failed.png
    這里發(fā)生了這些:
    python manage.py test polls去polls應(yīng)用找tests
    如果發(fā)現(xiàn)了django.test.TestCase的子類
    它會為測試創(chuàng)建一個特殊的數(shù)據(jù)庫
    查找test開頭的 測試方法
    在這里就是找到test_was_published_recently_with_future_question蛮寂,創(chuàng)建一個日期在一個月以后的Question
    調(diào)用斷言assertIs()方法蔽午,發(fā)現(xiàn)返回Ture,跟希望的False不一致酬蹋,然后給出上面的提示及老。

  • 發(fā)現(xiàn)了bug抽莱,就要修復(fù)。在polls/models.py
    class Question(models.Model):
          ...
          def was_published_recently(self):
              now = timezone.now()
              return now-datetime.timedelta(days=1) <= self.pub_date <= now
    

    重新跑骄恶,可以看到
    test_polls_success.png

    更多綜合測試

    def test_was_published_recently_with_old_question(self):
        time = timezone.now() - datetime.timedelta(days=30)
        old_question = Question(pub_date=time)
        self.assertIs(old_question.was_published_recently(), False)
    
    def test_was_published_recently_with_recent_question(self):
        time = timezone.now() - datetime.timedelta(hours=1)
        recent_question = Question(pub_date=time)
        self.assertIs(recent_question.was_published_recently(), True)
    

  • 測試views食铐。剛才我們在代碼本身找bug,接下來可以在與用戶交互的界面上來找找問題僧鲁。
    django提供了一個測試的客戶端模擬器來測試view虐呻,我們可以在tests.py和shell使用。
    我們從shell用:
    >>> from django.test.utils import setup_test_environment
    >>> setup_test_environment()
    
    setup_test_environment()方法安裝了一個可以模版渲染的東西寞秃。這個方法不會建立測試的數(shù)據(jù)庫斟叼,所有的都會運(yùn)行在當(dāng)前存在的數(shù)據(jù)庫上并且輸出的結(jié)果可能跟你已經(jīng)創(chuàng)建的會有一點(diǎn)點(diǎn)的區(qū)別,比如如果你在settings.py里設(shè)置的TIME_ZONE不對春寿,那么你的結(jié)果就會不大一樣朗涩,為了避免這個,檢查一下TIME_ZONE的設(shè)置绑改。
    使用client類
    >>> from django.test import Client
    >>> client = Client()
    >>> response = client.get("/")
    # Not Found: /
    >>> response.status_code
    # 404
    >>> from django.urls import reverse
    >>> response = client.get(reverse('polls:index'))
    >>> response.status_code
    # 200
    >>> response.content
    >>> response.context['latest_question_list']
    

  • 提升我們的view谢床,在polls/views.py的IndexView類里,我們修改一下get_queryset()厘线,使它在查詢的時候可以把日期和當(dāng)前日期比對一下:
    from django.utils import timezone
         class IndexView(generic.ListView):
                ...
                def get_queryset(self):
                    return Question.objects.filter(pub_date__lte=timezone.now()).order('-pub_date')[:5]
    
    這里的filter返回了一個包含日期早于或等于Question的查詢集萤悴,__lte(注意是2條_)是django數(shù)據(jù)模型日期屬性的一個固定寫法,用在filter方法里皆的,屬性__lte=日期表示日期早于或等于指定的那個日期覆履。
  • 測試我們的新的view,在tests.py里:
    from django.urls import reverse
    def create_question(question_text, days):
        time = timezone.now() + date time.timedelta(days=days)
        return Question.objects.create(question_test=question_text, pub_date=time)
    
    class QuestionViewTests(TestCase):
          def test_index_view_with_no_question(self):
              response = self.client.get(reverse('polls:index'))
              self.assertEqual(response.status_code, 200)
              self.assertContains(response, "No polls are available")
              self.assertQuesrysetEqual(response.context['latest_question_list'], [])
    
          def test_index_view_with_a_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.>'])
    
          def test_index_view_with_a_future_question(self):
              create_question(question_text="Future question", days=30)
              response = self.client.get('polls:index')
              self.assertQuerysetEqual(response.context['latest_question_list'], [])
    
          def test_index_view_with_future_question_and_past_question(self):
              create_question(question_text="Past question.", days=-30)
              create_question(question_text="Future question.", days=30)
              response = self.client.get(reverse('polls:index'))
              self.assertQuerysetEqual(response.context['latest_question_list'], ['<Question: question.>'])
    
          def test_index_view_with_two_past_questions(self):
              create_question(question_text="Past question 1.", days=-30)
              create_question(question_text="Past question 2.", days=-5)
              response = self.client.get(reverse('polls:index'))
              self.assertQuerysetEqual(response.context['latest_question_list'],['<Question: Past question 1.>', '<Question: Past question 2.>'])
    
    下面來仔細(xì)看:
    create_question()是快捷創(chuàng)建question的方法
    test_index_view_with_no_question不創(chuàng)建任何的question對象费薄,而是驗(yàn)證latest_question_list是否是空的硝全。
    執(zhí)行每一個測試方法的時候測試數(shù)據(jù)庫都會重置。

  • 測試DetailView
    目前日期是未來的question不會顯示到index.html里楞抡,但是如果用戶猜出來了正確的URL伟众,那還是能獲得這些未來日期的question,所以要在DetailView里加一個類似的約束:
    class DetailView(generic.DetailView):
          ...
          def get_queryset(self):
              return Question.objects.filter(pub_date__lte=timezone.now())
    
    在test.py里
    class QuestionIndexDetailTests(TestCase):
          def test_detail_view_with_a_future_question(self):
              future_question = create_question(question_text='Future question.', days=5)
              url = reverse('polls:detail', args=(future_question.id,))
              response=self.client.get(url)
              self.assertEqual(response.status_code, 404)
    
          def test_detail_view_with_a_past_question(self):
              past_question=create_question(question_text='Past question.', days=-5)
              url=reverse('polls:detail', args=(past_question.id,))
              response=self.client.get(url)
              self.assertContains(response, past_question.question_text)
    
    以上是測試的部分召廷。

part 6

  • 定制app的外觀凳厢。
    web app除了HTML以外,還需要諸如圖片竞慢,JS文件或者CSS先紫,這些一般都是靜態(tài)文件,我們可以用django.contrib.staticfiles來應(yīng)對這些:對于小的app可以放在指定的地方而不需要用這個模塊筹煮,對于大的應(yīng)用用這個統(tǒng)一管理比較好遮精。
    首先在polls文件夾下創(chuàng)建一個static文件夾,類似templates。
    django的STATICFILES_FINDERS設(shè)置包含了一系列的finder本冲,這些finder定義了查找靜態(tài)文件的方式准脂。其中有一個叫做AppDirectoriesFinder的會在每一個INSTALLED_APPS里查找一個叫做static的文件夾。
    在這個static文件夾里創(chuàng)建一個polls文件夾檬洞,在這個polls文件夾里再創(chuàng)建一個style.css文件狸膏,所以這個css文件的地址是polls/static/polls/style.css
    在這個style.css文件里:
    li a {
        color: green;
    }
    
    接下來在polls/templates/polls/index.html里的最頂部添加:
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}"></link>
    
    {% static %}生成了靜態(tài)文件的絕對路徑添怔。重新加載http://127.0.0.1:8000/polls/你可以看到問題的鏈接變成原諒色了湾戳。

  • 添加一張背景圖。
    polls/static/polls/下創(chuàng)建一個用來放置圖片的images文件夾澎灸。在文件夾里放一張background.gif圖片,所以這張圖片的路徑是polls/static/polls/images/background.gif遮晚。
    在style.css里
    body {
        background: white url("images/background.gif") no-repeat right bottom;
    }
    
    重新加載就能看到背景圖的效果
    part5-6就到這里性昭。
    戳這里查看下面的教程:Django入門-從0開始編寫一個投票網(wǎng)站(四)(完結(jié))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市县遣,隨后出現(xiàn)的幾起案子糜颠,更是在濱河造成了極大的恐慌,老刑警劉巖萧求,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件其兴,死亡現(xiàn)場離奇詭異,居然都是意外死亡夸政,警方通過查閱死者的電腦和手機(jī)元旬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來守问,“玉大人匀归,你說我怎么就攤上這事『呐粒” “怎么了穆端?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長仿便。 經(jīng)常有香客問我体啰,道長,這世上最難降的妖魔是什么嗽仪? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任荒勇,我火速辦了婚禮,結(jié)果婚禮上闻坚,老公的妹妹穿的比我還像新娘枕屉。我一直安慰自己,他們只是感情好鲤氢,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布搀擂。 她就那樣靜靜地躺著西潘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哨颂。 梳的紋絲不亂的頭發(fā)上喷市,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音威恼,去河邊找鬼品姓。 笑死,一個胖子當(dāng)著我的面吹牛箫措,可吹牛的內(nèi)容都是我干的腹备。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼斤蔓,長吁一口氣:“原來是場噩夢啊……” “哼植酥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弦牡,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤友驮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后驾锰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卸留,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年椭豫,在試婚紗的時候發(fā)現(xiàn)自己被綠了耻瑟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡赏酥,死狀恐怖匆赃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情今缚,我是刑警寧澤算柳,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站姓言,受9級特大地震影響瞬项,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜何荚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一囱淋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧餐塘,春花似錦妥衣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜂筹。三九已至,卻和暖如春芦倒,著一層夾襖步出監(jiān)牢的瞬間艺挪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工兵扬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留麻裳,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓器钟,卻偏偏與公主長得像津坑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子傲霸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容