Source

djangobook-cn / docs / _build / pickle / _sources / 2.0 / chapter03.txt

Full commit
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
.. _2.0-chapter03:

======================
第3章: View と URLconf
======================

前章で、私たちは Django プロジェクトを作成し、
Django 開発用サーバを起動する方法を解説しました。
この章では、Django で動的なWebページを作成するための基本を学びます。

初めての Django で動作するページ: Hello world
---------------------------------------------

私たちの最初の目標として、
決まり文句 "Hello world" を出力するWebページを作ってみましょう。

もしあなたが、Webフレームワークを使わずに、
単純に "Hello world" と出力するだけのWebページを作成した場合は、
単純に "Hello world" と書いたテキストファイルを `hello.html` 
等の名前で保存し、
Webサーバ内のディレクトリーにアップロードするだけです。

このプロセスで、あなたはWebページに関する2つの重要な情報を
決定していることに注目してください。
その内容("Hello world"という文字列)と、
そのURL( `http://www.example.com/hello.html
<http://www.example.com/hello.html>`_ もしくは、
あなたがサブディレクトリーにアップロードしたのであれば、
おそらく `http://www.example.com/files/hello.html
<http://www.example.com/files/hello.html>`_ )です。

Django では、同様に2つの情報を指定しますが、
指定方法が異なっています。
ページの内容は *View 関数* が生成し、
URL は *URLconfs* で指定します。
最初に、私たちの "Hello world" View 関数を書いてみましょう。

初めての View
~~~~~~~~~~~~~

前章で、 `django-admin.py startproject` により作成した `mysite` ディレクトリー内に、 
`views.py` という名前のファイルを作成してください。
この Python モジュールは、この章の View に該当しています。 
`views.py` という名前に特別な意味はないので注意してください - 
もう少し後で解説しますが、Django にファイルの名前は関係ありません。
しかし、これは `views.py` と呼ぶのが慣習であり、
あなたのコードを他の開発者が読みやすいため、良い考えです。

私たちの "Hello world" View 関数は非常に単純です。
ここに、 
`import` 宣言を含む全ての関数があるので、
あなたはこれを `views.py` に入力する必要があります。

.. code-block:: python

    from django.http import HttpResponse

    def hello(request):
        return HttpResponse("Hello world")

このコードの各行ごとに、そのステップを解説します。

* 最初の行で、私たちは `django.http` モジュール内にある 
  `HttpResponse` クラスをインポートしています。
  私たちはこのクラスをコード内で利用するので、
  それをインポートする必要があります。

* 次の行で、 `hello` という名前の関数を定義しています - View 関数

  各 View 関数は、少なくとも1つ以上の引数を受け取り、
  慣習では `request` という名前が使われています。
  これは、この View を呼び出した Web リクエストに関する情報を含んでおり、
  それは `django.http.HttpRequest` クラスのインスタンスです。
  この例では、私たちは `request` に対して何も操作していませんが、
  それは View 関数の最初の引数である必要があります。

  View 関数の名前に特別な意味はないので注意してください; 
  それを Django に通知するために特定の規則に基づく名前を付ける必要はありません。
  私たちは、View の目的を明確に示すために `hello` という名前にしていますが、
  それは、 `hello_wonderful_beautiful_world` 、または他の名前を付けることもできます。
  次の "はじめての URLconf" セクションでは、
  Django がどのようにしてこの機能を見つけるかに光を当てます。

* 最後の行は、この関数の(1行の単純な)処理です; 
  それは単に "Hello world" という文字列を引数とした、 `HttpResponse` 
  オブジェクトを返すだけです。

主なレッスンは以下の通りです:
View はただの Python 関数であり、
最初の引数として、 `HttpRequest` を受け取り、 
`HttpResponse` インスタンスを返します。
Django の View は、Python の関数であるため、
2点に注意する必要があります。
(これについては、例外として後ほど解説します。)

初めての URLconf
~~~~~~~~~~~~~~~~

もしこの時点で、あなたが再び `python manage.py runserver` を実行しても、
私たちの "Hello world" というメッセージはどこにも表示されず、
まだ "Welcome to Django" というメッセージが表示されます。
なぜなら、私たちの `mysite` プロジェクトが、
まだ `hello` View を知らないからです。
私たちは、 Django に対し、
特定の URL で、どの View を呼び出すかを明確に指定する必要があります。
(上記の、静的な HTML ファイルを公開する例でいうところの、
HTMLの作成を終え、まだディレクトリーにアップロードされていない状態と類比しています。)
Django で、特定の URL に View をフックするためには、URLconf を利用します。

URLconf は、あなたの Django ベースの Web サイトの目次のようなものです。
その基本動作は、URL パターンと、
そのURL パターンで呼び出される View 関数をマッピングします。
それはあなたが、
「この URL はこの関数を呼ぶ、その URL はその関数を呼ぶ」という風に Django に伝えます。
例えば、
「誰かが URL `/foo/` を表示したら、 
Python モジュール `views.py` の `foo_view()` という View 関数を呼ぶ」という風に伝えます。

あなたが、前章で `django-admin.py startproject` を実行した時に、
このスクリプトが自動的にあなたの URLconf を作成しました: 
`urls.py` ファイル。
デフォルトでは、このようになっているでしょう。

.. code-block:: python

    from django.conf.urls.defaults import *

    # Uncomment the next two lines to enable the admin:
    # from django.contrib import admin
    # admin.autodiscover()

    urlpatterns = patterns('',
        # Example:
        # (r'^mysite/', include('mysite.foo.urls')),

        # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
        # to INSTALLED_APPS to enable admin documentation:
        # (r'^admin/doc/', include('django.contrib.admindocs.urls')),

        # Uncomment the next line to enable the admin:
        # (r'^admin/', include(admin.site.urls)),
    )

デフォルトの URLconf には、
一般的に使われるいくつかの Django 機能がコメントアウトされているので、
その機能の起動はとても簡単で、該当の行をコメントアウトするだけです。
コメントアウトされているコードを除くと、
URLconf に必要不可欠な部分はここです:

.. code-block:: python

    from django.conf.urls.defaults import *

    urlpatterns = patterns('',
    )

このコードの各行ごとに、そのステップを解説します。

* 最初の行は、Django の URLconf 基盤である 
  `django.conf.urls.defaults` 内のすべてのモジュールをインポートしています。
  これには、 `patterns` という名前の関数が含まれています。

* 次の行は、 `patterns` 関数で、
  その戻り値を `urlpatterns` という変数に格納しています。 
  `patterns` 関数はひとつだけ引数を受け取っています - 
  例では空文字です。
  (この文字列は、View 関数にプレフィクス (prefix) 引数を渡すために用いますが、
  私たちは今のところこの上級テクニックの解説はしません。)

ここで注意すべき重要なことは、
Django は、あなたの URLconf モジュールから 
`urlpatterns` 変数を探すということです。
この変数は、URL と、
その URL から呼び出すコード(例えば View 関数)のマッピングを定義します。
デフォルトでは、私たちが見たとおり、URLconf は空です - 
あなたの Django アプリケーションはまっさらの状態(Blank Slate)です。
(脚注として、この状態は前章にあるように "Welcome to Django" ページを表示します。
あなたの URLconf が空の場合、
Django はあなたが新しいプロジェクトを始めたばかりと仮定し、
そのメッセージを表示します。)

URLconf に、URL と View 関数を追加するには、
URL パターンから View 関数へマップする Python のタプルを追加します。
私たちの `hello` View を呼び出すためには以下のようにします:

.. code-block:: python

    from django.conf.urls.defaults import *
    from mysite.views import hello

    urlpatterns = patterns('',
        ('^hello/$', hello),
    )

(私たちは、コードを簡略化するために、
コメントアウトされているコードを省いています。
もしあなたが、それらの行を残しておきたいのであれば、
残しておいても構いません。)

私たちはここで2箇所を変更しました。

* 最初に、私たちは `mysite/views.py` モジュールから、 
  `hello` View をインポートするために、
  Python のインポート構文で、 `mysite.views` をインポートしました。
  (これは、 `mysite/views.py` があなたの Python パス上にあると仮定しています。
  詳細は下記の *あなたの Python パス* を参照してください。)

* 次に、私たちは `urlpatterns` に、 `('^hello/$', hello)` を追加しました。
  この行は、 *URLpattern* と呼ばれています。
  それは、最初の要素がパターンマッチ用の文字列(正規表現など)で、
  次の要素がそのパターンが利用する View 関数である Python タプルです。
  簡単に言うと、私たちは、 `hello` という URL へのどんなリクエストでも、
  `hello` View 関数を呼び出すように Django に指定しました。

.. admonition:: あなたの Python パス

    あなたが Python の `import` 構文を利用する際に Python が見るのは、
    あなたの *Python パス* は、あなたのシステムディレクトリーの一覧です。

    例えば、あなたの Python パスが、 
    `['', '/usr/lib/python2.4/site-packages', '/home/username/djcode']` 
    だったとします。
    もしあなたが、 `from foo import bar` という Python 構文を発行した場合は、
    Python は、カレントディレクトリー(この構文を発行したディレクトリー)内の `foo.py` を探します。
    (Python パスの最初の要素である空文字 `''` は、"カレントディレクトリー"を意味しています。)
    もしそのファイルが見つからない場合、
    Pythonは、 `/usr/lib/python2.4/site-packages/foo.py` を探します。
    そのファイルが見つからない場合は、 `/home/username/djcode/foo.py` を探します。
    最後に、そのファイルを見つけられなかった場合は、 
    `ImportError` を発生させます。

    もし、あなたが自身の Python パスを見てみたいのであれば、
    Python のインタラクティブシェルを起動し、以下を入力してください。

    .. code-block:: python

        >>> import sys
        >>> print sys.path

    通常、あなたは Python パスの設定について心配する必要はありません - 
    Python や Django は、その内部で自動的にそれを解決しています。
    (Python パスの設定は、 `manage.py` スクリプトの仕事の一つです。)

この URLpattern 構文をすぐに理解できるように、
これについてディスカッションしてみましょう。
私たちは `/hello/` という URL にマッチさせたいのですが、
パターンがそれとは異なるように見えるかもしれません。
それには以下のような理由があります:

* Djangoは、URLpatterns をチェックする前に、
  すべての URL から先頭のスラッシュを削除します。
  これは、私たちの URLpattern が `/hello/` の先頭のスラッシュを含まないことを意味しています。
  (これは、最初戸惑うかもしれませんが、この要求は物事を単純化します - 
  第8章で解説しますが、URLconfs に、他の URLconfs をインクルードする場合など。)

* パターンは、キャレット記号( `^` )と、ドル記号( `$` )を含んでいます。
  これは特別な意味を持つ正規表現の文字です。
  キャレット記号は「文字列の開始指定にマッチするパターン」を意味しており、
  またドル記号は「文字列の終了指定にマッチするパターン」を意味しています。

  この概念を例によって解説します。
  もし私たちが、仮にパターン `'^hello/'` (ドル記号で終わっていない)を利用した場合、
  `/hello/` だけでなく、 `/hello/foo` や `/hello/bar` のような 
  URLが `/hello/` から始まるすべての URL にマッチしてしまいます。
  同様に、私たちがキャレット記号を削除 (例えば `'hello/$'` )した場合、
  Django は、 `foo/bar/hello/` のような 
  URLが `/hello/` で終わるすべての URL にマッチさせます。
  私たちがキャレット記号やドル記号を使わず、単純に `hello/` とした場合、 
  `foo/hello/bar/` のような 
  URLに `hello/` が含まれるすべての URL にマッチしてしまいます。
  このように、URL `/hello/` だけにマッチすることを保証するために、
  私たちはキャレット記号とドル記号を使います - 
  それ以上でも以下でもありません。

  多くの URLpatterns は、キャレット記号で始まり、ドル記号で終わりますが、
  より詳細なマッチを実現するために素敵な柔軟性を持っています。

  あなたは、誰かが `/hello` (スラッシュ `なし` )でリクエストした場合について、
  疑問に思うかもしれません。
  私たちの URLpatterns にはスラッシュが指定されているので、
  その URL にはマッチしません。
  しかし、デフォルトで、URLpatterns にマッチせず、
  スラッシュで終わっていないすべてのリクエストは、
  スラッシュ付きの同じ URL へリダイレクトされます。
  (これは、Django 設定の `APPEND_SLASH` 設定により管理されており、
  「付録 E」で解説します。)

  もしあなたが、全ての URL がスラッシュで終わる形式が好きなのであれば
  (Django 開発者が好きかどうか)、
  すべての各 URLpattern にスラッシュを追加し、 
  `APPEND_SLASH` の設定を `True` のままにしてください。
  もしあなたが、スラッシュで終わらない URL 形式が好きなのであれば、
  もしくは各 URL 毎にそれを決めたいのであれば、
  `APPEND_SLASH` を `False` に設定して、
  あなたの URLpattern の適切な箇所にスラッシュを追加してください。

この URLconf について他に注目すべきことは、 
`hello` View 関数がオブジェクトのようであり関数を呼び出していないことです。
これは Python の(そしてその他の動的言語の)主要な機能です。

関数は第一級オブジェクト(ファーストクラスオブジェクト: first-class object)であり、
それはあなたが関数を他の変数と同様に取り扱えることを意味しています。
素晴らしいと思いませんか?

URLconf の変更をテストするために、
第2章で実行したように 
`python manage.py runserver` コマンドを実行し、
Django 開発用サーバを起動してください。

(もしあなたがそれを起動したままにしておいても大丈夫です。
開発用サーバはあなたの Python コードの変更箇所を自動的に感知し、
必要に応じてリロードするので、
あなたは変更毎にサーバを再起動する必要ありません。)
サーバは `http://127.0.0.1:8000/` のアドレスで起動されているので、
Web ブラウザを開き `http://127.0.0.1:8000/hello/` を表示してください。

あなたは "Hello world" という文字を確認できるでしょう - 
あなたの Django View が出力した文字列。

おめでとうございます!
あなたは最初の Django で動作するページを完成させました。

.. admonition:: 正規表現

    正規表現(以下 *regex* )は、
    文字列のパターンを指定するための簡潔な方法です。
    Django の URLconfs は URL の強力なマッチ処理のために
    任意の regex を利用できますが、
    恐らくあなたが利用する regex のシンボルは2~3個でしょう。
    一般的なシンボルは以下の通りです。

    +--------------+--------------------------------------------------+
    | シンボル     | マッチ                                           |
    +==============+==================================================+
    | `.` (ドット) | 任意の文字                                       |
    +--------------+--------------------------------------------------+
    | `\d`         | 任意の数値                                       |
    +--------------+--------------------------------------------------+
    | `[A-Z]`      | A~Z(大文字)の任意の文字                       |
    +--------------+--------------------------------------------------+
    | `[a-z]`      | a~z(小文字)の任意の文字                       |
    +--------------+--------------------------------------------------+
    | `[A-Za-z]`   | A~z(大文字小文字を含む)の任意の文字           |
    +--------------+--------------------------------------------------+
    | `+`          | 直前の表現が 1 (個) 以上                         |
    +--------------+--------------------------------------------------+
    | `[^/]+`      | スラッシュを含まない文字列                       |
    +--------------+--------------------------------------------------+
    | `?`          | 直前の表現が 0 (個)、または1個                   |
    +--------------+--------------------------------------------------+
    | `*`          | 直前の表現が 0 (個)以上                          |
    |              | (例えば `d*` はゼロ、または複数桁の数値にマッチ) |
    +--------------+--------------------------------------------------+
    | `{1,3}`      | 直前の表現が 1~3 (個) まで                      |
    |              | (例えば `d{1,3}` は 1、2、3 にマッチ)            |
    +--------------+--------------------------------------------------+

    正規表現に関する詳細については、 `http://www.djangoproject.com/r/python/re-module/
    <http://www.djangoproject.com/r/python/re-module/>`_ を参照してください。
    日本語ドキュメントとしては、 `http://www.python.jp/doc/release/lib/module-re.html
    <http://www.python.jp/doc/release/lib/module-re.html>`_ が参考になります。

早わかり 404 エラー
~~~~~~~~~~~~~~~~~~~

この時点で、私たちの URLconf は、ひとつの URLpattern だけを定義しています: 
それは URL `/hello/` へのリクエストを処理するものです。
もしあなたが、この URL ではない URL に対してリクエストをしたらどうなるでしょうか?

確認のために、
Django 開発用サーバを起動し、 
`http://127.0.0.1:8000/goodbye/` 、
`http://127.0.0.1:8000/hello/subdirectory/` 、
`http://127.0.0.1:8000/` 
(サイトの "ルート")のようなページを
表示してください。

あなたは、 "Page not found" というメッセージ(「図3-2」を参照)と遭遇します。

.. figure:: ../_static/2.0/chapter03/404.png
   :alt: Django の 404 ページのスクリーンショット
   :align: center

   図3-2 Django の 404 ページ

このページのユーティリティは、
ただの基本的な 404 エラーメッセージではありません。
それは、URLconf 内のすべてのパターンと、
Django が使っている URLconf を正確にあなたに伝えます。
その情報から、
あなたはリクエストされた URL が、
なぜ 404 を返したかを見分けることができます。

当然、これは Web 開発者のあなただけが知りうる機密情報です。
もし、これが商用サイトであり、インターネット上にデプロイしているのであれば、
あなたはその情報を公開したくないと思うでしょう。
それは、あなたの Django プロジェクトが *デバッグモード* で起動されているため、
この "Page not found" ページが表示されているだけです。
私たちは、後でデバッグモードを無効化する方法について解説します。
今のところ、あなたが最初に Django プロジェクトを作成した時は、
それがデバッグモードになっていることを覚えておいてください。
また、プロジェクトがデバッグモードでない場合は、
異なる 404 応答を Django が返すことを覚えておいてください。

早わかり サイトルート
~~~~~~~~~~~~~~~~~~~~~

最後のセクションで解説したように、
あなたがサイトのルートを表示すると、
あなたは 404 エラーメッセージに遭遇します - `http://127.0.0.1:8000/` 。
Django は魔法を使ってサイトルートに何かを追加したりはしません: 
その URL が(どんな場合においても)特別扱いされるわけではありません。
それは、あなたの URLconf 内の他のエントリーと同様に、
それを割り当てるかどうかはあなた次第です。

しかし、サイトルートにマッチする URLpattern は直感的ではないので、
それに言及する価値はあります。
あなたがサイトルートにマッチする View を用意する方法は、
空文字にマッチする `'^$'` を利用してください。

例は以下の通りです。

.. code-block:: python

    urlpatterns = patterns('',
        ('^$', my_homepage_view),
        # ...
    )

Django のリクエスト処理プロセス
-------------------------------

私たちの次の View 関数に進む前に、
手を休めて、もう少し Django の動作について学びましょう。
詳細について、
あなたが Web ブラウザーから 
`http://127.0.0.1:8000/hello/` を表示し、
あなたの "Hello world" メッセージが表示されるまでに、
Django の内部でどんな動作をしているのかを解説します。

すべての始まりは `settings.py` ファイルです。
あなたが `python manage.py runserver` を実行すると、
スクリプトは、 `manage.py` と同じディレクトリ内にある 
`settings.py` という名前のファイルを探します。
このファイルは、その特定の Django プロジェクトのための、
様々な(すべて大文字の)構成を含みます: 
`TEMPLATE_DIRS` 、 `DATABASE_NAME` 等。
最も重要なのは、 `ROOT_URLCONF` という名前の設定です。 
`ROOT_URLCONF` は、この Web サイトで、
どの Python モジュールが URLconf として使われるかを Django に伝えます。

`django-admin.py startproject` コマンドで、 
`settings.py` と`urls.py` ファイルを作成したのを覚えていますか?
自動生成された `settings.py` は、
その時点では自動生成された `urls.py` が `ROOT_URLCONF` に設定されています。 
`settings.py` ファイルを開いて、あなた自身で見てみてください; 
それは、以下のようになっているでしょう:

.. code-block:: python

    ROOT_URLCONF = 'mysite.urls'

これは、 `mysite/urls.py` ファイルのことです。
特定のURLでリクエストをもらう(仮定では `/hello/` へのリクエスト)と、
Django は、 `ROOT_URLCONF` で指定されたURLconfをロードします。
そしてリクエストされた URL と、
URLconf 内の各 URLpattern を1つずつ順番に比較し、
それがマッチするのを見つけるまでチェックします。
マッチするのを見つけると、
そのパターンに紐付け(ひもづけ)られた View 関数を呼び、
関数への最初の引数として HttpRequest オブジェクトを渡します。
(私たちは、後ほど HttpRequest の詳細を解説します。)

私たちの、はじめての View の例のように、
View 関数はHttpResponseを返さなければなりません。
一度返すと、残りの、
Python オブジェクトを HTTP ヘッダーやボディー(例えば Web ページのコンテンツ)からなる
適切な Web レスポンスに変換する作業はDjango がやってくれます。

要約すると:

#. `/hello/` リクエストをもらいます。

#. Django は、 `ROOT_URLCONF` 設定を見て、URLconf のルートを決定します。

#. Django は、URLconf 内のすべての URLpattern を参照し、
   最初の `/hello/` にマッチするのを見つけます。

#. マッチするのを見つけると、それに紐付け(ひもづけ)られた View 関数を呼びます。

#. View 関数は、 `HttpResponse` を返します。

#. Django は `HttpResponse` を Web ページとして、
   適当なHTTPレスポンスに変換して返します。

今、あなたは Django で動作するページを作成する基本的な方法を知ることができました。
それは本当に単純です - 
View 関数を書いて、URLconf でその URL をマップするだけです。

2つめの View: 動的コンテンツ
----------------------------

私たちの "Hello world" View は、
Django の基本的な動作のデモンストレーションとしては有効でしたが、
それはページコンテンツが常に同じため、
動的な Web ページの例とはなりません。
あなたはいつ `/hello/` を見ても、同じものを見ます; 
それは、静的HTMLファイルで十分です。

私たちの2つめの View として、より動的なものを作ってみましょう - 
現在の日付と時刻を表示する Web ページ。
それはデータベースや、ユーザーからの何らかのインプットも含んでいないため、
次の単純で素晴らしいステップです - 
それはあなたのサーバーの内部時計を出力するだけです。
"Hello world" より、ちょっとだけわくわくするだけですが、
それは新しい概念も少し含んでいます。

この View は、2つのことをする必要があります: 
現在の日付と時刻を計算し、その値を含む HttpResponse を返します。
あなたが Python の経験がある場合は、
Python が日付を計算するためには `datetime` モジュールを
インクルードするのをご存じでしょう。
その使用方法は以下の通りです。

.. code-block:: python

    >>> import datetime
    >>> now = datetime.datetime.now()
    >>> now
    datetime.datetime(2009, 3, 17, 14, 53, 26, 305000)
    >>> print now
    2009-03-17 14:53:26.305000
    >>>

それはとても単純であり、Django とは関係がありません。
これはただの Python コードです。
(私たちは、あなたがそのコードが "ただの Python" コードなのか、
Django 特有のコードなのかを把握することを重要視しています。
私たちは、あなたが Django について学習するだけでなく、
あなたが必ずしも Django を利用するわけではないので、
他の Python プロジェクトにも適用できるようになって欲しいと思っています。)

Django が現在の日付と時刻を表示する View を作成するためには、
私たちは、この `datetime.datetime.now()` 構文を含む View 関数を書き、 
`HttpResponse` として返す必要があります。

その方法は以下の通りです:

.. code-block:: python

    from django.http import HttpResponse
    import datetime

    def current_datetime(request):
        now = datetime.datetime.now()
        html = "<html><body>It is now %s.</body></html>" % now
        return HttpResponse(html)

私たちの `hello` View 関数同様に、
これは `views.py` 内にいる必要があります。
私たちは、コードを簡略化するために、 
`hello` 関数を省いていることに注意してください。
すべてが記述された `views.py` は以下の通りです:

.. code-block:: python

    from django.http import HttpResponse
    import datetime

    def hello(request):
     return HttpResponse("Hello world")

    def current_datetime(request):
       now = datetime.datetime.now()
       html = "<html><body>It is now %s.</body></html>" % now
       return HttpResponse(html)

(私たちは、今後必要な場合を除き、コード例に以前のコードを含みません。
あなたは、文脈を通してコード例のどの部分が新しいか、
また古いかを見分けることができるはずです。)

私たちが、 `current_datetime` を提供するための 
`views.py` の変更点をステップ毎に見てみましょう。

* 私たちは、上部で `datetime` モジュールをインポートしたので、
  日付を計算することができます。

* 新しい `current_datetime` 関数は、 
  `datetime.datetime` オブジェクトとして現在の日付と時刻を計算し、
  それを `now` ローカル変数として保存します。

* View 内の2行目のコードは、
  Python の "文字列フォーマット" 操作を利用し、
  HTML レスポンスを作っています。

* `%s` を含む文字列はプレースホルダであり、
  パーセント記号の後ろの部分は、
  「 `now` 変数の値で、文字列内の `%s` を変換する」
  を意味しています。 
  `now` 変数は、厳密にいえば文字列ではなく、 
  `datetime.datetime` オブジェクトでありませんが、 
  `%s` フォーマット文字は、それを `"2009-03-17 14:53:26.305000"` のような
  代表的な文字列に変換します。
  これは、 
  `"<html><body>It is now 2009-03-17 14:53:26.305000.</body></html>"` のような 
  HTML 文字列を返します。

  (私たちのHTMLは正しくありませんが、私たちは例を簡単で短くしたいと思っています。)

* 最後に、View は生成したレスポンスを含む 
  `HttpResponse` オブジェクトを返します - 
  それは私たちが `hello` でやったことと同じです。

それを `views.py` に追加した後、
どの URL がこの View を呼び出すかを Django に伝えるために、
URLpattern を `urls.py` に追加してください。
分かりやすい `/time/` のようなのがいいでしょう:

.. code-block:: python

    from django.conf.urls.defaults import *
    from mysite.views import hello, current_datetime

    urlpatterns = patterns('',
        ('^hello/$', hello),
        ('^time/$', current_datetime),
    )

私たちはここで2点を変更しました。
最初に、私たちは上部で `current_datetime` 関数をインポートしました。
次に、より重要なこととして、
私たちは URL `/time/` とその新しい View の URLpattern マッピングを追加しました。
このコツをつかめましたか?

新しく書いた View と更新された URLconf で `runserver` を開始し、
あなたのブラウザーから `http://127.0.0.1:8000/time/` を見てください。
あなたは、現在の日付と時刻を見るでしょう。

.. admonition:: Django のタイムゾーン

    あなたのコンピュータに依存し、日付と時刻は少しずれているかもしれません。
    それは Django がタイムゾーンを意識しており、
    デフォルトが `America/Chicago` のタイムゾーンだからです。
    (それはデフォルトを指定しなければならず、
    それは Django 開発者が住んでいることろです。)
    あなたがどこか他の場所に住んでいるのであれば、 
    `settings.py` で変更することができます。
    そのファイルのコメントに、
    設定可能な全世界のタイムゾーンの最新の一覧へのリンクが記載されています。

URLconf と疎結合
----------------

今は、URLconf の裏側の、
そしてそれは大方 Django の裏側の鍵となる哲学に注目するのに良い時間でしょう: 
*疎結合* の原則です。
簡単に言うと、疎結合は、交換可能な部品の重要性を評価するソフトウェア開発アプローチです。
2つのコードが疎結合の場合、部品のうち1つに対する変更は、もう1つにほとんど影響を及ぼしません。

Django の URLconf は、この原則を理解するのに良い例です。
Django の Web アプリケーションでは、
それが呼ぶ URLconf と View 関数は疎結合です; 
つまり、特定の関数に対する URL の決定と、
関数そのもの処理は、2つの別々の場所に存在します。
これは、あなたが他に影響を及ぼすことなく、1つの部品だけ変更することができます。

例えば、私たちの `current_datetime` View について考えてみましょう。
もし私たちが、アプリケーションの URL を変更したいのであれば
(例えば `/time/` から `/current-time/` へ)、
View そのものは考慮する必要がなく、
私たちはそれを迅速に URLconf の変更だけでできます。
同様に、私たちがView関数を変更したいのであれば
(例えば、そのロジックの変更、他のパイソンモジュールへの移動等)、
私たちは、その関数が紐付けられている URL に影響を及ぼすことなく変更することができます。

さらに、私たちが *いくつか* の URL で、現在日時を表示させたいのであれば、
View コードに触れず、
私たちは URLconf を編集するだけで簡単にそれを実現できます。
この例では、私たちの `current_datetime` は、2つの URL で利用できます。
これは不自然な例ですが、このテクニックは何かと重宝します:

.. code-block:: python

    urlpatterns = patterns('',
        ('^hello/$', hello),
        ('^time/$', current_datetime),
        ('^another-time-page/$', current_datetime),
    )

URLconfs と View は疎結合に動作します。
私たちは、この本を通してこの重要な哲学を例示し続けたいと思います。

3つめの View: 動的 URL
----------------------

私たちの、 `current_datetime` View は、
ページのコンテンツは動的(現在日時)でしたが、
URL ( `/time/` ) は静的でした。

動的な Web アプリケーションの大多数は、
URL 内にページの出力に影響するパラメータを含んでいます。
例えばオンライン書店では、 
`/books/243/` 、 
`/books/81196/` 等、 
各本それぞれにURLを割り当てているかもしれません。

指定された数の時間と、現在時刻を相殺した時間を表示する3つめの View を作りましょう。
ゴールは、 
`/time/plus/1/` が1時間後を表示するページ、 
`/time/plus/2/` は2時間後を表示するページ、 
`/time/plus/3/` は3時間後を表示するページ等を含む一連のサイトを作成します。

初心者の方は、相殺する各時間で 別々の View 関数のコードを思いつき、
以下のような URLconf を書いてしまうかもしれません:

.. code-block:: python

    urlpatterns = patterns('',
        ('^time/$', current_datetime),
        ('^time/plus/1/$', one_hour_ahead),
        ('^time/plus/2/$', two_hours_ahead),
        ('^time/plus/3/$', three_hours_ahead),
        ('^time/plus/4/$', four_hours_ahead),
    )

この行には明らかに欠点があります。
余分な View 関数があるだけでなく、
このアプリケーションは、あらかじめ定義された時間しかサポートしません - 
1、2、3、4時間。
もし私たちが、将来 *5* 時間後を表示するページを作成する場合、
私たちはその個別の View と URLconf 行を作成しなければならず、
それは明らかに重複しています。
私たちは、いくつか抽象化する必要があります。

.. admonition:: 美しい URL について

    もしあなたが、他の Web 開発 プラットフォーム(例えばPHP、Javaなど)の経験があれば、
    「QueryStringパラメータを使えばいいのでは?」と感じるかもしれません - 
    `/time/plus?hours=3` のように、 
    `hours` を URLの QueryString ( `?` に続く文字列)
    のパラメータとして渡すようにデザインする。

    Django でもそうすることが *でき* ます
    (私たちはあなたに第7章で解説します)が、
    Django の重要な哲学の1つに URL は美しくなければなりません。
    `/time/plus/3/` という URL の方が、
    より綺麗で、より単純で、より読みやすく、
    口に出して誰かに伝えるのがより簡単であり、
    そして、… QueryString よりも明らかに美しいです。

    美しい URL は、良質な Web アプリケーションの特徴です。
    Django の URLconf システムは美しい URL を推奨しており、
    美しい URL を使わないよりも、使った方が簡単です。

私たちはどのように任意の相殺時間を取り扱えるよう
アプリケーションを設計するのでしょうか?
鍵は *ワイルドカード URLpattern* を利用することです。
私たちが前に言ったように、URLpattern は正規表現です; 
私たちは、1桁以上の数値にマッチさせるために、
正規表現パターン `\d+` を利用することができます。

.. code-block:: python

    urlpatterns = patterns('',
        # ...
        (r'^time/plus/\d+/$', hours_ahead),
        # ...
    )

(私たちは、この例から省略された他の URLpattern が
あるかもしれないという意味で `# ...` を使います。)

この URLpattern は、例えば 
`/time/plus/2/` 、 
`/time/plus/25/` 、もしくは 
`/time/plus/100000000000/` 等どんな URL にもマッチします。

そういえば、相殺を許可する時間の最大値を 99時間に制限してみましょう。
それは、私たちが1から2桁のどちらかの数値のみを許可することを意味し、
それを正規表現で表すと、 `\d{1,2}` となります。

.. code-block:: python

    (r'^time/plus/\d{1,2}/$', hours_ahead),

.. admonition:: 注意

    Web アプリケーションを構築するにあたり、
    異常なデータ入力について考慮する必要があり、
    アプリケーションがサポートする入力値を決定するのは常に重要です。
    私たちは、相殺する時間を99時間に制限することにより、
    異常値を制限しました。

私たちがあなたに紹介したいもう一つの重要なポイントは、
正規表現文字列の前にある `r` という文字です。
これは Python に、
この文字列が「raw 文字列 (raw string) 」であることを伝えます - 
その文字列の内容は、バックスラッシュを解釈しません。
通常、Python での文字列は、
バックスラッシュが特殊文字をエスケープするために使いす - 
例えば、改行文字を含む文字は `\n` となります。
あなたが raw 文字列としてそれに `r` を加えると、
Python はエスケープされたバックスラッシュを適用しません - 
そのため、`\n` は、
文字通りのバックスラッシュと小文字の "n" を含んだ文字列です。
Python でのスラッシュと、
正規表現内のバックスラッシュは衝突するため、
あなたがパイソンで正規表現を定義する場合は、
いつも raw 文字列の使用を強く推奨します。

いま、私たちは URL にワイルドカードを指定しましたが、
View 関数にそのワイルドカードの情報を渡す方法が必要であり、
それにより相殺するどんな任意の時間も1つの View 関数で処理できるようになります。
私たちが、URLpattern から取得したいデータは括弧 `()` 内に置きます。
私たちの例の場合、
URLに入る数値を取得したいので、 
`\d{1,2}` を括弧内に置きましょう:

.. code-block:: python

    (r'^time/plus/(\d{1,2})/$', hours_ahead),

あなたが正規表現をよく知っているならば、
ここは理解しやすいでしょう; 
マッチした文字列からデータを取得するために括弧を使う。

最終的に、私たちが前に作成した 2 つの View を含む URLconf は以下のようになります。

.. code-block:: python

    from django.conf.urls.defaults import *
    from mysite.views import hello, current_datetime, hours_ahead

    urlpatterns = patterns('',
        (r'^hello/$', hello),
        (r'^time/$', current_datetime),
        (r'^time/plus/(\d{1,2})/$', hours_ahead),
    )

これを処理するための、 `hours_ahead` View を書いてみましょう。

.. admonition:: コーディング順序

    この例では、私たちは最初に URLpattern を書き、
    次に View を書きましたが、
    前の例では、最初に View、次に URLpattern を書きました。
    どちらの手法がいいのでしょうか?

    それは、開発者により異なります。

    あなたがトップダウン型の開発者であれば、
    プロジェクトがスタートすると、
    一気に必要な URLpattern を書きあげ、
    それから View を書くかもしれません。
    これはあなたに明確な To-Do リストを提供するという長所があり、
    それは主として、あなたが書く View 関数に必要なパラメータを定めます。

    あなたがボトムアップ型の開発者であれば、
    最初に View を書き、その後でその URL を定義するのを好むかもしれません。
    これも問題ありません。

    結論からすると、
    どちらの手法を選ぶかは、あなたの考え方に会っている方がベストです。

    双方のアプローチ共に有効です。

`hours_ahead` は、鍵となる違い以外は、
私たちが前に書いた `current_datetime` View と、非常に似ています: 
それは、相殺時間のための変数を受け取ります。

View コードは以下の通りです。

.. code-block:: python

    def hours_ahead(request, offset):
        offset = int(offset)
        dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
        html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
        return HttpResponse(html)

このコードの各行ごとに、そのステップを解説します。

* `hours_ahead` View 関数は、2つの引数を受け取ります: `request` と `offset` 。

  * `request` は、 `hello` や `current_datetime` と同様に `HttpRequest` オブジェクトです。
    私たちは再度復習したいと思います: 
    各 View は、その最初の引数として、常に `HttpRequest` オブジェクトを受け取ります。

  * `offset` は、URLpattern の括弧から取得した文字列です。
    例えば、リクエストされたURLが `/time/plus/3/` の場合、
    `offset` は `"3"` という文字列です。
    例えば、リクエストされたURLが `/time/plus/21/` の場合、
    `offset` は `"21"` という文字列です。
    取得した値は、数値ではなく文字列であることに注意しなければならず、
    それが例え `'21'` のような数値のみの場合でも文字となります。

    (技術的に、取得した値は Python のバイト文字列ではなく、
    それは常に *Unicode オブジェクト* ですが、
    今のところこの区別については心配しないでください)

    我々は変数名を `offset` に決めましたが、
    有効な Python の識別子であれば、
    あなたが好きな名前をつけても構いません。
    変数名は、重要でありません; 
    それが、View に対する `request` の後に続く、
    第2の引数であることが重要です。

    (それは、位置というよりはむしろ、
    URLconfの変数としてキーワードの使用を有効にするためです。
    私たちは、それについて第8章で解説します。)

* 私たちが View 関数内で最初にすることは、 
  `offset` に対して `int()` 関数を呼ぶことです。
  これは、文字列を整数値に変換します。

  あなたが `int` を呼んだ場合、
  例えば `foo` 等の整数値に変換できない値を指定すると、
  Python が `ValueError` 例外をスローすることに注意してください。
  しかしこの例では、私たちは `offset` に文字列ではなく
  整数値が入ってくるのが確実なので、
  私たちはその例外をキャッチする必要はありません。
  なぜなら、私たちの URLpattern 内の正規表現 - 
  `(\d{1,2})` - は数値のみを取得するからです。
  これは URLconfs のもう1つの素敵な例証です: 
  それは、入力値について、限られてはいるが、
  使い易いある程度のバリデーションを提供しています。

* View 関数の次の行で、
  私たちは現在の日付/時刻を計算し、時間数を加算します。
  私たちはすでに、 `current_datetime` View 関数で、 
  `datetime.datetime.now()` を見ています。
  ここでの新しい概念は、
  あなたが `datetime.timedelta` オブジェクトを作成し、 
  `datetime.datetime` オブジェクトへ加算することによって
  日付/時刻の演算を行うことができるということです。

  私たちは結果を `dt` 変数へ保存しています。

  この行は、私たちが `offset` に対して `int` を呼ぶ理由を示しており、 
  `datetime.timedelta` 関数は、時間の引数は整数値である必要があります。

* 次の行は、私たちが `current_datetime` でやったのと同様に、
  この View 関数の HTML 出力を生成します。
  前の行と、この行の小さな違いは、
  Python の フォーマット文字機能が2つの値を利用することです。
  そのため、文字列内に2つの `%s` シンボルと、
  挿入するタプル( `offset` 、 `dt` )があります。

* 最後の行で、私たちは HTML の `HttpResponse` を返します。
  今になると、この説明は不要ですよね?

新しく書いた View と更新された URLconf で Django の開発用サーバを起動し
(もし、それを起動していない場合は)、
あなたのブラウザーから `http://127.0.0.1:8000/time/plus/3/` を見て、
その動作を確認してください。
次に、 `http://127.0.0.1:8000/time/plus/5/` を試してください。
次は、 `http://127.0.0.1:8000/time/plus/24/` です。
最後に、 `http://127.0.0.1:8000/time/plus/100/` を見て、
あなたの URLconf が1~2桁の数値のみを許可するかを確認してください; 
私たちが前のセクション "早わかり 404 エラー" で確認したように、
この場合 Django は、"Page not found" エラーを表示します。
また、 `http://127.0.0.1:8000/time/plus/` (時間指定が *ない* )も404となります。

Django の素敵なエラーページ
---------------------------

私たちが、ここまでで作成した素晴らしい Web アプリケーションに
浸ってください … すぐにそれを壊します! 
`hours_ahead` 関数で `offset = int(offset)` の行をコメントアウトすることにより、 
`views.py` ファイルで故意に Python エラーを発生させましょう。

.. code-block:: python

    def hours_ahead(request, offset):
        #offset = int(offset)
        dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
        html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
        return HttpResponse(html)

最後にこの情報の多くが機密なのは言うまでもなく
(それは、あなたの Python コードと Django の構成の内部を公開します)、
インターネットにこの情報を公開するのは愚かなことです。
悪意のある人は、
あなたの Web アプリケーションをリバースエンジニアリングし、
何かしらの攻撃のために、それを利用されることになります。
その理由から、Django エラーページは、
あなたの Django プロジェクトがデバッグモードの時のみ表示するべきです。
我々は、第20章でデバッグモードを無効にする方法を解説します。
今のところ、あなたが Django プロジェクトをスタートした時点では、
自動的にデバッグモードになっているということを覚えておいてください。
(聞き覚えがありますか?
この章の始めに解説した "Page not found" エラーと同様の動作です。)

次章について
------------

ここまで私たちは、Python コードで HTML をハードコードしたものを、
直接 View 関数に書いていました。
これは私たちが基礎概念のデモンストレーションが簡単になるようにそうしましたが、
現実の世界では、この考え方は間違っています。

Django は、ページのデザインを内部のコードから切り離すことができ、
簡単ですが強力なテンプレートエンジンを持っています。

:ref:`次の章 <2.0-chapter04>` では、
Django のテンプレートエンジンを学びます。