アプリをDjango0.96から1.0に移植する—Djangoのドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/releases/1.0-porting-guide
移動先:案内検索

アプリをDjango0.96から1.0に移植する

Django 1.0は、一部の領域で0.96との互換性を失います。

このガイドは、0.96のプロジェクトとアプリを1.0に移植するのに役立ちます。 このドキュメントの最初の部分には、1.0で実行するために必要な一般的な変更が含まれています。 最初の部分を実行してもコードが壊れてしまう場合は、あまり一般的でない変更のセクションで、あまり一般的でない互換性の問題のリストを確認してください。

も参照してください

1.0リリースノート。 このドキュメントでは、1.0の新機能についてさらに詳しく説明しています。 移植ガイドは、コードをすばやく更新できるようにすることに関心があります。


一般的な変更

このセクションでは、ほとんどのユーザーが行う必要のある0.96と1.0の間の変更について説明します。

Unicodeを使用する

文字列リテラル('foo')をUnicodeリテラル(u'foo')に変更します。 Djangoは全体でUnicode文字列を使用するようになりました。 ほとんどの場所で、生の文字列は引き続き機能しますが、Unicodeリテラルを使用するように更新すると、いくつかのあいまいな問題を防ぐことができます。

詳細については、 Unicodeデータを参照してください。


モデル

モデルファイルへの一般的な変更:

maxlengthの名前をmax_lengthに変更します

maxlength引数の名前をmax_lengthに変更します(これはフォームフィールドと一致するように変更されました)。


__str__を__unicode__に置き換えます

モデルの__str__関数を__unicode__メソッドに置き換え、そのメソッドで Unicodeu'foo')を使用していることを確認してください。


prepopulated_fromを削除します

モデルフィールドのprepopulated_from引数を削除します。 無効になり、admin.pyModelAdminクラスに移動されました。 管理者への変更の詳細については、以下の管理者を参照してください。


coreを削除します

モデルフィールドからcore引数を削除します。 同等の機能(インライン編集の一部)が管理インターフェースによって異なる方法で処理されるようになったため、これは不要になりました。 以下の admin セクションに到達するまで、インライン編集について心配する必要はありません。 今のところ、coreへのすべての参照を削除します。


class Admin:をadmin.pyに置き換えます

モデルからすべての内部class Admin宣言を削除します。 あなたがそれらを残しても彼らは何も壊しませんが、彼らはまた何もしません。 管理者にアプリを登録するには、それらの宣言をadmin.pyファイルに移動します。 詳細については、以下の管理者を参照してください。

も参照してください

djangosnippets の寄稿者が、models.pyをスキャンして対応するadmin.py を生成するスクリプトを作成しました。


以下は、必要なすべての変更を含むmodels.pyファイルの例です。

古い(0.96)models.py

class Author(models.Model):
    first_name = models.CharField(maxlength=30)
    last_name = models.CharField(maxlength=30)
    slug = models.CharField(maxlength=60, prepopulate_from=('first_name', 'last_name'))

    class Admin:
        list_display = ['first_name', 'last_name']

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

新規(1.0)models.py

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    slug = models.CharField(max_length=60)

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

新規(1.0)admin.py

from django.contrib import admin
from models import Author

class AuthorAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name']
    prepopulated_fields = {
        'slug': ('first_name', 'last_name')
    }

admin.site.register(Author, AuthorAdmin)

管理者

1.0での最大の変更点の1つは、新しい管理者です。 Django管理インターフェース(django.contrib.admin)は完全にリファクタリングされました。 管理者定義はモデル定義から完全に分離され、フレームワークはDjangoの新しいフォーム処理ライブラリを使用するように書き直され、拡張性とカスタマイズを念頭に置いて再設計されました。

実際には、これはすべてのclass Admin宣言を書き直す必要があることを意味します。 上記のモデルで、[X105X] をadmin.pyファイルのadmin.site.register()呼び出しに置き換える方法をすでに説明しました。 以下は、そのAdmin宣言を新しい構文に書き直す方法の詳細です。

新しいインライン構文を使用する

新しいedit_inlineオプションはすべてadmin.pyに移動されました。 次に例を示します。

古い(0.96):

class Parent(models.Model):
    ...

class Child(models.Model):
    parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)

新規(1.0):

class ChildInline(admin.StackedInline):
    model = Child
    extra = 3

class ParentAdmin(admin.ModelAdmin):
    model = Parent
    inlines = [ChildInline]

admin.site.register(Parent, ParentAdmin)

詳細については、 InlineModelAdminオブジェクトを参照してください。


fieldsを簡略化するか、fieldsetsを使用します

古いfields構文は非常に紛らわしく、簡略化されています。 古い構文は引き続き機能しますが、代わりにfieldsetsを使用する必要があります。

古い(0.96):

class ModelOne(models.Model):
    ...

    class Admin:
        fields = (
            (None, {'fields': ('foo','bar')}),
        )

class ModelTwo(models.Model):
    ...

    class Admin:
        fields = (
            ('group1', {'fields': ('foo','bar'),   'classes': 'collapse'}),
            ('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
        )

新規(1.0):

class ModelOneAdmin(admin.ModelAdmin):
    fields = ('foo', 'bar')

class ModelTwoAdmin(admin.ModelAdmin):
    fieldsets = (
        ('group1', {'fields': ('foo','bar'),   'classes': 'collapse'}),
        ('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
    )

も参照してください

  • 変更とその背後にある理由の詳細については、 NewformsAdminBranchwikiページを参照してください。
  • 新しい管理者には、たくさんの新機能が付属しています。 それらについては、管理ドキュメントで読むことができます。


URL

ルートを更新するurls.py

管理サイトを使用している場合は、ルートurls.pyを更新する必要があります。

古い(0.96)urls.py

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^admin/', include('django.contrib.admin.urls')),

    # ... the rest of your URLs here ...
)

新規(1.0)urls.py

from django.conf.urls.defaults import *

# The next two lines enable the admin and load each admin.py file:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),

    # ... the rest of your URLs here ...
)

ビュー

newformsの代わりにdjango.formsを使用してください

django.newformsdjango.formsに置き換えます– Django1.0はnewformsモジュール(0.96で導入)の名前をプレーンな古いformsに変更しました。 oldformsモジュールも削除されました。

すでにnewformsライブラリを使用していて、推奨されるimportステートメント構文を使用している場合は、インポートステートメントを変更するだけです。

年:

from django import newforms as forms

新しい:

from django import forms

古いフォームシステム(以前はdjango.formsおよびdjango.oldformsと呼ばれていました)を使用している場合は、フォームを書き直す必要があります。 開始するのに適した場所は、フォームのドキュメントです。


新しいAPIを使用してアップロードされたファイルを処理する

アップロードされたファイル(つまり、request.FILESのエントリ)の使用を単純な辞書として新しい UploadedFile に置き換えます。 古い辞書の構文は機能しなくなりました。

したがって、次のようなビューで:

def my_view(request):
    f = request.FILES['file_field_name']
    ...

…次の変更を加える必要があります。

古い(0.96) 新規(1.0)
f['content'] f.read()
f['filename'] f.name
f['content-type'] f.content_type


新しいAPIを使用してファイルフィールドを操作する

django.db.models.FileField の内部実装が変更されました。 これの目に見える結果は、これらのモデルフィールドの特別な属性(URL、ファイル名、画像サイズなど)にアクセスする方法が変更されたことです。 モデルの FileFieldmyfileと呼ばれると仮定して、次の変更を行う必要があります。

古い(0.96) 新規(1.0)
myfile.get_content_filename() myfile.content.path
myfile.get_content_url() myfile.content.url
myfile.get_content_size() myfile.content.size
myfile.save_content_file() myfile.content.save()
myfile.get_content_width() myfile.content.width
myfile.get_content_height() myfile.content.height

widthおよびheight属性は、 ImageField フィールドに対してのみ意味があることに注意してください。 詳細については、モデルAPI のドキュメントをご覧ください。


ObjectPaginatorの代わりにPaginatorを使用してください

0.96のObjectPaginatorは削除され、改善されたバージョン django.core.paginator.Paginator に置き換えられました。


テンプレート

自動エスケープを愛することを学ぶ

デフォルトでは、テンプレートシステムはすべての変数の出力を自動的にHTMLエスケープするようになりました。 詳細については、自動HTMLエスケープを参照してください。

個々の変数の自動エスケープを無効にするには、:tfilter: `safe` フィルターを使用します。

This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}

テンプレート全体の自動エスケープを無効にするには、テンプレート(またはテンプレートの特定のセクションのみ)を:ttag: `autoescape` タグでラップします。

{% autoescape off %}
   ... unescaped template content here ...
{% endautoescape %}

あまり一般的ではない変更

次の変更は、より小さく、よりローカライズされた変更です。 これらは上級ユーザーにのみ影響するはずですが、リストを読んでコードでこれらのことを確認することはおそらく価値があります。

信号

  • 登録済みのシグナルハンドラーに**kwargsを追加します。
  • django.dispatch.dispatcherのモジュールメソッドではなく、 Signal オブジェクトのメソッドを介して信号を接続、切断、および送信します。
  • AnonymousおよびAny送信者オプションの使用をすべて削除します。 それらはもう存在しません。 sender=Noneを使用すると、どの送信者からも送信された信号を受信できます。
  • 宣言したカスタムシグナルを、匿名オブジェクトではなく django.dispatch.Signal のインスタンスにします。

必要なコード変更の概要は次のとおりです。

古い(0.96) 新規(1.0)
def callback(sender) def callback(sender, **kwargs)
sig = object() sig = django.dispatch.Signal()
dispatcher.connect(callback, sig) sig.connect(callback)
dispatcher.send(sig, sender) sig.send(sender)
dispatcher.connect(callback, sig, sender=Any) sig.connect(callback, sender=None)


コメント

Django0.96のdjango.contrib.commentsアプリを使用していた場合は、1.0で導入された新しいコメントアプリにアップグレードする必要があります。 詳細については、アップグレードガイドを参照してください。


テンプレートタグ

:ttag: `スペースレス` タグ

spacelessテンプレートタグは、単一のスペースを保持する代わりに、HTMLタグ間のすべてのスペースを削除するようになりました。


地元の味

我ら 地元の味

django.contrib.localflavor.usadjango.contrib.localflavor.usに名前が変更されました。 この変更は、他のローカルフレーバーの命名スキームと一致するように行われました。 コードを移行するには、インポートを変更するだけです。


セッション

新しいセッションキーの取得

SessionBase.get_new_session_key()_get_new_session_key()に名前が変更されました。 get_new_session_object()はもう存在しません。


備品

行をロードしてもsave()が呼び出されなくなりました

以前は、行をロードすると、モデルのsave()メソッドが自動的に実行されていました。 これはもはや当てはまらないため、save()によって自動入力されたフィールド(タイムスタンプなど)には、フィクスチャに明示的な値が必要になります。


設定

より良い例外

古いEnvironmentErrorは、Djangoが設定モジュールを見つけられなかったときにImportErrorに分割され、すでに使用した後で設定を再構成しようとするとRuntimeErrorに分割されました。


:setting: `LOGIN_URL` が移動しました

:setting: `LOGIN_URL` 定数がdjango.contrib.authからsettingsモジュールに移動しました。 使用する代わりにfrom django.contrib.auth import LOGIN_URL参照する :setting: `settings.LOGIN_URL `


:setting: `APPEND_SLASH` の動作が更新されました

0.96では、URLがスラッシュで終わっていないか、パスの最後のコンポーネントにピリオドがあり、:setting: `APPEND_SLASH` がTrueの場合、Djangoは同じURLにリダイレクトしますが、末尾にスラッシュが追加されています。 これで、Djangoは、末尾にスラッシュがないパターンがURLパターン内の何かと一致するかどうかを確認します。 その場合、意図的にそのパターンをキャッチしたいと想定されているため、リダイレクトは行われません。

ほとんどの人にとって、これは変更を必要としません。 ただし、次のようなURLパターンを持っている人もいます。

r'/some_prefix/(.*)$'

以前は、これらのパターンは、末尾にスラッシュがあるようにリダイレクトされていました。 このようなURLで常にスラッシュが必要な場合は、パターンを次のように書き直してください。

r'/some_prefix/(.*/)$'

小さなモデルの変更

get()とは異なる例外

マネージャーは、AssertionErrorではなく MultipleObjectsReturned 例外を返すようになりました。

古い(0.96):

try:
    Model.objects.get(...)
except AssertionError:
    handle_the_error()

新規(1.0):

try:
    Model.objects.get(...)
except Model.MultipleObjectsReturned:
    handle_the_error()

LazyDateが解雇されました

LazyDateヘルパークラスはもう存在しません。

デフォルトのフィールド値とクエリ引数はどちらも呼び出し可能なオブジェクトである可能性があるため、LazyDateのインスタンスをdatetime.datetime.nowへの参照に置き換えることができます。

古い(0.96):

class Article(models.Model):
    title = models.CharField(maxlength=100)
    published = models.DateField(default=LazyDate())

新規(1.0):

import datetime

class Article(models.Model):
    title = models.CharField(max_length=100)
    published = models.DateField(default=datetime.datetime.now)

DecimalFieldは新しく、FloatFieldは適切なフロートになりました

古い(0.96):

class MyModel(models.Model):
    field_name = models.FloatField(max_digits=10, decimal_places=3)
    ...

新規(1.0):

class MyModel(models.Model):
    field_name = models.DecimalField(max_digits=10, decimal_places=3)
    ...

この変更を忘れると、__init__max_digits属性を取得しないFloatFieldに関するエラーが表示されます。これは、新しいFloatFieldが精度をとらないためです-関連する引数。

MySQLまたはPostgreSQLを使用している場合、それ以上の変更は必要ありません。 DecimalFieldのデータベース列タイプは、古いFloatFieldの場合と同じです。

SQLiteを使用している場合は、データベースに適切な列を浮動小数点ではなく10進型として表示させる必要があります。 これを行うには、データをリロードする必要があります。 コードでDecimalFieldを使用するように変更し、Djangoコードを更新した後で、これを行います。

警告

最初にデータベースをバックアップしてください!

SQLiteの場合、これはデータベースを格納する単一のファイルのコピーを作成することを意味します(そのファイルの名前はsettings.pyファイルのDATABASE_NAMEです)。


DecimalFieldを使用するように各アプリケーションをアップグレードするには、以下のコードの<app>を各アプリの名前に置き換えて、次の操作を実行できます。

$ ./manage.py dumpdata --format=xml <app> > data-dump.xml
$ ./manage.py reset <app>
$ ./manage.py loaddata data-dump.xml

ノート:

  1. このプロセスの最初のステップでは、XML形式を使用することを忘れないでください。 SQLiteを使用してfloatを10進数に移植できるようにするXMLデータダンプの機能を活用しています。
  2. 2番目のステップでは、問題のアプリケーションのデータを失う準備ができていることを確認するように求められます。 イエスと言う; このデータは3番目のステップで復元します。
  3. DecimalFieldは、この変更が行われる前にDjangoに同梱されていたアプリでは使用されていないため、標準のDjangoモデルでこの手順を実行することを心配する必要はありません。

上記のプロセスで問題が発生した場合は、バックアップしたデータベースファイルを元のファイルにコピーして、最初からやり直してください。


国際化

django.views.i18n.set_language()でPOSTリクエストが必要になりました

以前は、GETリクエストが使用されていました。 古い動作は、状態(サイトの表示に使用されるロケール)がGETリクエストによって変更される可能性があることを意味していました。これは、HTTP仕様の推奨事項に反しています。 このビューを呼び出すコードは、GETではなくPOSTリクエストが行われるようにする必要があります。 つまり、リンクを使用してビューにアクセスすることはできなくなりますが、何らかのフォーム送信を使用する必要があります(例: ボタン)。


_()は組み込みではなくなりました

_()(名前が単一のアンダースコアである呼び出し可能オブジェクト)は、組み込みにモンキーパッチされなくなりました。つまり、すべてのモジュールで魔法のように利用できなくなりました。

以前は_()が常に存在することに依存していた場合は、必要に応じてugettextまたはugettext_lazyを明示的にインポートし、自分で_にエイリアスする必要があります。

from django.utils.translation import ugettext as _

HTTP要求/応答オブジェクト

HttpRequestへの辞書アクセス

HttpRequestオブジェクトは、辞書スタイルのアクセスを直接サポートしなくなりました。 以前は、GETPOSTの両方のデータがHttpRequestオブジェクトで直接利用可能でした(たとえば、if 'some_form_key' in requestまたはrequest['some_form_key']を読んでください。 これはサポートされなくなりました。 GETPOSTを組み合わせたデータにアクセスする必要がある場合は、代わりにrequest.REQUESTを使用してください。

ただし、受信する予定の要求のタイプ(request.GETまたはrequest.POST)については、常に適切な辞書を明示的に調べることを強くお勧めします。 結合されたrequest.REQUESTディクショナリに依存すると、受信データの発信元を隠すことができます。


HTTPResponseヘッダーへのアクセス

django.http.HttpResponse.headers_headersに名前が変更され、 HttpResponse は包含チェックを直接サポートするようになりました。 したがって、if header in response.headers:の代わりにif header in response:を使用してください。


一般的な関係

一般的な関係はコアから移動されました

汎用リレーションクラス– GenericForeignKeyおよびGenericRelation –は django.contrib.contenttypes モジュールに移動しました。


テスト

django.test.Client.login()が変更されました

古い(0.96):

from django.test import Client
c = Client()
c.login('/path/to/login','myuser','mypassword')

新規(1.0):

# ... same as above, but then:
c.login(username='myuser', password='mypassword')

管理コマンド

コードから管理コマンドを実行する

django.core.management が大幅にリファクタリングされました。

コード内の管理サービスへの呼び出しでは、call_commandを使用する必要があります。 たとえば、flushとload_dataを呼び出すテストコードがある場合:

from django.core import management
management.flush(verbosity=0, interactive=False)
management.load_data(['test_data'], verbosity=0)

…次のようにコードを変更する必要があります。

from django.core import management
management.call_command('flush', verbosity=0, interactive=False)
management.call_command('loaddata', 'test_data', verbosity=0)

サブコマンドはオプションの前に置く必要があります

django-admin.pyおよびmanage.pyでは、オプションの前にサブコマンドが必要になりました。 そう:

$ django-admin.py --settings=foo.bar runserver

…機能しなくなったため、次のように変更する必要があります。

$ django-admin.py runserver --settings=foo.bar

シンジケーション

Feed.__init__が変更されました

シンジケーションフレームワークのFeedクラスの__init__()メソッドは、フィードのURLではなく、HttpRequestオブジェクトを2番目のパラメーターとして受け取るようになりました。 これにより、サイトフレームワークを必要とせずにシンジケーションフレームワークを機能させることができます。 これは、Feedをサブクラス化し、__init__()メソッドをオーバーライドするコード、およびFeed.__init__()を直接呼び出すコードにのみ影響します。


データ構造

SortedDictFromListはなくなりました

django.newforms.forms.SortedDictFromListは削除されました。 django.utils.datastructures.SortedDictは、タプルのシーケンスでインスタンス化できるようになりました。

コードを更新するには:

  1. django.newforms.forms.SortedDictFromListを使用していた場所では、django.utils.datastructures.SortedDictを使用してください。
  2. django.utils.datastructures.SortedDict.copySortedDictFromList.copy()のようにディープコピーを返さないため、ディープコピーに依存している場合はコードを更新する必要があります。 copy.deepcopyを直接使用してこれを行います。


データベースバックエンド関数

データベースバックエンド関数の名前が変更されました

データベースバックエンドレベル関数のほぼすべての名前が変更されているか、再配置されています。 これらのいずれも文書化されていませんが、これらの関数のいずれかを使用している場合は、コードを変更する必要があります。これらの関数はすべて django.db にあります。

古い(0.96) 新規(1.0)
backend.get_autoinc_sql connection.ops.autoinc_sql
backend.get_date_extract_sql connection.ops.date_extract_sql
backend.get_date_trunc_sql connection.ops.date_trunc_sql
backend.get_datetime_cast_sql connection.ops.datetime_cast_sql
backend.get_deferrable_sql connection.ops.deferrable_sql
backend.get_drop_foreignkey_sql connection.ops.drop_foreignkey_sql
backend.get_fulltext_search_sql connection.ops.fulltext_search_sql
backend.get_last_insert_id connection.ops.last_insert_id
backend.get_limit_offset_sql connection.ops.limit_offset_sql
backend.get_max_name_length connection.ops.max_name_length
backend.get_pk_default_value connection.ops.pk_default_value
backend.get_random_function_sql connection.ops.random_function_sql
backend.get_sql_flush connection.ops.sql_flush
backend.get_sql_sequence_reset connection.ops.sequence_reset_sql
backend.get_start_transaction_sql connection.ops.start_transaction_sql
backend.get_tablespace_sql connection.ops.tablespace_sql
backend.quote_name connection.ops.quote_name
backend.get_query_set_class connection.ops.query_set_class
backend.get_field_cast_sql connection.ops.field_cast_sql
backend.get_drop_sequence connection.ops.drop_sequence_sql
backend.OPERATOR_MAPPING connection.operators
backend.allows_group_by_ordinal connection.features.allows_group_by_ordinal
backend.allows_unique_and_pk connection.features.allows_unique_and_pk
backend.autoindexes_primary_keys connection.features.autoindexes_primary_keys
backend.needs_datetime_string_cast connection.features.needs_datetime_string_cast
backend.needs_upper_for_iops connection.features.needs_upper_for_iops
backend.supports_constraints connection.features.supports_constraints
backend.supports_tablespaces connection.features.supports_tablespaces
backend.uses_case_insensitive_names connection.features.uses_case_insensitive_names
backend.uses_custom_queryset connection.features.uses_custom_queryset