# Django 3.2.11.dev - dokumentacja

# Porting your apps from Django 0.96 to 1.0

Django 1.0 breaks compatibility with 0.96 in some areas.

This guide will help you port 0.96 projects and apps to 1.0. The first part of this document includes the common changes needed to run with 1.0. If after going through the first part your code still breaks, check the section Less-common Changes for a list of a bunch of less-common compatibility issues.

Zobacz także

The 1.0 release notes. That document explains the new features in 1.0 more deeply; the porting guide is more concerned with helping you quickly update your code.

## Common changes

This section describes the changes between 0.96 and 1.0 that most users will need to make.

### Use Unicode

Change string literals (`'foo'`) into Unicode literals (`u'foo'`). Django now uses Unicode strings throughout. In most places, raw strings will continue to work, but updating to use Unicode literals will prevent some obscure problems.

See Unicode data for full details.

### Modele

Common changes to your models file:

#### Rename `maxlength` to `max_length`

Rename your `maxlength` argument to `max_length` (this was changed to be consistent with form fields):

#### Replace `__str__` with `__unicode__`

Replace your model’s `__str__` function with a `__unicode__` method, and make sure you use Unicode (`u'foo'`) in that method.

#### Remove `prepopulated_from`

Remove the `prepopulated_from` argument on model fields. It’s no longer valid and has been moved to the `ModelAdmin` class in `admin.py`. See the admin, below, for more details about changes to the admin.

#### Remove `core`

Remove the `core` argument from your model fields. It is no longer necessary, since the equivalent functionality (part of inline editing) is handled differently by the admin interface now. You don’t have to worry about inline editing until you get to the admin section, below. For now, remove all references to `core`.

#### Replace `class Admin:` with `admin.py`

Remove all your inner `class Admin` declarations from your models. They won’t break anything if you leave them, but they also won’t do anything. To register apps with the admin you’ll move those declarations to an `admin.py` file; see the admin below for more details.

Zobacz także

A contributor to djangosnippets has written a script that’ll scan your models.py and generate a corresponding admin.py.

#### Example

Below is an example `models.py` file with all the changes you’ll need to make:

Old (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)

New (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)

New (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)

### The Admin

One of the biggest changes in 1.0 is the new admin. The Django administrative interface (`django.contrib.admin`) has been completely refactored; admin definitions are now completely decoupled from model definitions, the framework has been rewritten to use Django’s new form-handling library and redesigned with extensibility and customization in mind.

Practically, this means you’ll need to rewrite all of your `class Admin` declarations. You’ve already seen in models above how to replace your `class Admin` with an `admin.site.register()` call in an `admin.py` file. Below are some more details on how to rewrite that `Admin` declaration into the new syntax.

#### Use new inline syntax

The new `edit_inline` options have all been moved to `admin.py`. Here’s an example:

Old (0.96):

    class Parent(models.Model):
        ...

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

New (1.0):

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

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

    admin.site.register(Parent, ParentAdmin)

See InlineModelAdmin objects for more details.

#### Simplify `fields`, or use `fieldsets`

The old `fields` syntax was quite confusing, and has been simplified. The old syntax still works, but you’ll need to use `fieldsets` instead.

Old (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'}),
            )

New (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'}),
        )

Zobacz także

- More detailed information about the changes and the reasons behind them can be found on the NewformsAdminBranch wiki page
- The new admin comes with a ton of new features; you can read about them in the admin documentation.

### URLs

#### Update your root `urls.py`

If you’re using the admin site, you need to update your root `urls.py`.

Old (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 ...
    )

New (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 ...
    )

### Widoki

#### Use `django.forms` instead of `newforms`

Replace `django.newforms` with `django.forms` – Django 1.0 renamed the `newforms` module (introduced in 0.96) to plain old `forms`. The `oldforms` module was also removed.

If you’re already using the `newforms` library, and you used our recommended `import` statement syntax, all you have to do is change your import statements.

Old:

    from django import newforms as forms

New:

    from django import forms

If you’re using the old forms system (formerly known as `django.forms` and `django.oldforms`), you’ll have to rewrite your forms. A good place to start is the forms documentation

#### Handle uploaded files using the new API

Replace use of uploaded files – that is, entries in `request.FILES` – as simple dictionaries with the new `UploadedFile`. The old dictionary syntax no longer works.

Thus, in a view like:

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

…you’d need to make the following changes:

Old (0.96) | New (1.0)
--- | ---
`f['content']` | `f.read()`
`f['filename']` | `f.name`
`f['content-type']` | `f.content_type`

#### Work with file fields using the new API

The internal implementation of `django.db.models.FileField` have changed. A visible result of this is that the way you access special attributes (URL, filename, image size, etc.) of these model fields has changed. You will need to make the following changes, assuming your model’s `FileField` is called `myfile`:

Old (0.96) | New (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`

Note that the `width` and `height` attributes only make sense for `ImageField` fields. More details can be found in the model API documentation.

#### Use `Paginator` instead of `ObjectPaginator`

The `ObjectPaginator` in 0.96 has been removed and replaced with an improved version, `django.core.paginator.Paginator`.

### Szablony

#### Learn to love autoescaping

By default, the template system now automatically HTML-escapes the output of every variable. To learn more, see Automatic HTML escaping.

To disable auto-escaping for an individual variable, use the `safe` filter:

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

To disable auto-escaping for an entire template, wrap the template (or just a particular section of the template) in the `autoescape` tag:

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

## Less-common changes

The following changes are smaller, more localized changes. They should only affect more advanced users, but it’s probably worth reading through the list and checking your code for these things.

### Signals

- Add `**kwargs` to any registered signal handlers.
- Connect, disconnect, and send signals via methods on the `Signal` object instead of through module methods in `django.dispatch.dispatcher`.
- Remove any use of the `Anonymous` and `Any` sender options; they no longer exist. You can still receive signals sent by any sender by using `sender=None`
- Make any custom signals you’ve declared into instances of `django.dispatch.Signal` instead of anonymous objects.

Here’s quick summary of the code changes you’ll need to make:

Old (0.96) | New (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)`

### Komentarze

If you were using Django 0.96’s `django.contrib.comments` app, you’ll need to upgrade to the new comments app introduced in 1.0. See the upgrade guide for details.

### Tagi szablonu

#### `spaceless` tag

The `spaceless` template tag now removes all spaces between HTML tags, instead of preserving a single space.

### Local flavors

#### U.S. local flavor

`django.contrib.localflavor.usa` has been renamed to `django.contrib.localflavor.us`. This change was made to match the naming scheme of other local flavors. To migrate your code, all you need to do is change the imports.

### Sesje

#### Getting a new session key

`SessionBase.get_new_session_key()` has been renamed to `_get_new_session_key()`. `get_new_session_object()` no longer exists.

### Fixtures

#### Loading a row no longer calls `save()`

Previously, loading a row automatically ran the model’s `save()` method. This is no longer the case, so any fields (for example: timestamps) that were auto-populated by a `save()` now need explicit values in any fixture.

### Ustawienia

#### Ulepszone wyjątki

The old `EnvironmentError` has split into an `ImportError` when Django fails to find the settings module and a `RuntimeError` when you try to reconfigure settings after having already used them.

#### `LOGIN_URL` został przeniesiony

Stała `LOGIN_URL` została przeniesiona z `django.contrib.auth` do modułu `settings`. Zamiast używać `from django.contrib.auth import LOGIN_URL`, odwołaj się do `settings.LOGIN_URL`.

#### Zachowanie `APPEND_SLASH` zostało zaktualizowane

In 0.96, if a URL didn’t end in a slash or have a period in the final component of its path, and `APPEND_SLASH` was True, Django would redirect to the same URL, but with a slash appended to the end. Now, Django checks to see whether the pattern without the trailing slash would be matched by something in your URL patterns. If so, no redirection takes place, because it is assumed you deliberately wanted to catch that pattern.

Dla większości osób, ta zmiana nie będzie wymagała wprowadzenia żadnych zmian. Jeśli jednak posiadasz patterny URL wyglądające tak jak ten:

    r'/some_prefix/(.*)$'

Poprzednio te patterny zostałyby przekierowane tak, aby zawierały końcowy ukośnik. Jeśli chcesz zawsze posiadać ukośnik na takich URL-ach, przepisz pattern na:

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

### Mniejsze zmiany modeli

#### Different exception from `get()`

Manager-y od teraz zwracają wyjątek `MultipleObjectsReturned` zamiast `AssertionError`:

Old (0.96):

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

New (1.0):

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

#### `LazyDate` został zwolniony

Klasa pomocnicza `LazyDate` już nie istnieje.

Domyślne wartości pól i argumentów query mogą być także obiektami wywoływalnymi, dlatego instancje `LazyDate` mogą być zamienione na referencję do `datetime.datetime.now`:

Old (0.96):

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

New (1.0):

    import datetime

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

#### Nowe pole `DecimalField`, a `FloatField` jest od teraz poprawnym float-em.

Old (0.96):

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

New (1.0):

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

Jeśli zapomnisz dokonać tej zmiany, zobaczysz błędu mówiące, że `FloatField` nie przyjmuje atrybutu `max_digits` w `__init__`, gdyż nowy `FloatField` nie przyjmuje argumentów dotyczących jego precyzji.

Jeśli używasz MySQL albo PostgreSQL, żadne dodatkowe zmiany nie są wymagane. Typy kolumn bazy danych dla `DecimalField` są takie same jak dla starego `FloatField`.

Jeśli używasz SQLite, musisz wymusić na bazie danych traktowanie niektórych kolumn jako typ decimal zamiast jako float. Aby to zrobić, będziesz musiał ponownie wczytać swoje dane. Zrób to dopiero po tym jak zaktualizujesz kod Django i zmienisz typ pól na `DecimalField`.

Ostrzeżenie

Przed podjęciem jakichkolwiek działań, wykonaj kopię swojej bazy danych!

Dla SQLite oznacza to stworzenie kopii pojedynczego pliku, którzy przechowuje Twoją bazę danych (nazwa tego pliku jest zdefiniowana w stałej `DATABASE_NAME` w pliku settings.py).

To upgrade each application to use a `DecimalField`, you can do the following, replacing `<app>` in the code below with each app’s name:

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

Notatki:

1. It’s important that you remember to use XML format in the first step of this process. We are exploiting a feature of the XML data dumps that makes porting floats to decimals with SQLite possible.
2. In the second step you will be asked to confirm that you are prepared to lose the data for the application(s) in question. Say yes; we’ll restore this data in the third step.
3. `DecimalField` is not used in any of the apps shipped with Django prior to this change being made, so you do not need to worry about performing this procedure for any of the standard Django models.

If something goes wrong in the above process, just copy your backed up database file over the original file and start again.

### Internationalization

#### `django.views.i18n.set_language()` now requires a POST request

Previously, a GET request was used. The old behavior meant that state (the locale used to display the site) could be changed by a GET request, which is against the HTTP specification’s recommendations. Code calling this view must ensure that a POST request is now made, instead of a GET. This means you can no longer use a link to access the view, but must use a form submission of some kind (e.g. a button).

#### `_()` is no longer in builtins

`_()` (the callable object whose name is a single underscore) is no longer monkeypatched into builtins – that is, it’s no longer available magically in every module.

If you were previously relying on `_()` always being present, you should now explicitly import `ugettext` or `ugettext_lazy`, if appropriate, and alias it to `_` yourself:

    from django.utils.translation import ugettext as _

### Obiekty zapytania/odpowiedzi HTTP

#### Słownikowy dostęp do `HttpRequest`

`HttpRequest` objects no longer directly support dictionary-style access; previously, both `GET` and `POST` data were directly available on the `HttpRequest` object (e.g., you could check for a piece of form data by using `if 'some_form_key' in request` or by reading `request['some_form_key']`. This is no longer supported; if you need access to the combined `GET` and `POST` data, use `request.REQUEST` instead.

It is strongly suggested, however, that you always explicitly look in the appropriate dictionary for the type of request you expect to receive (`request.GET` or `request.POST`); relying on the combined `request.REQUEST` dictionary can mask the origin of incoming data.

#### Uzyskiwanie dostępu do nagłówków w `HTTPResponse`

Nazwa `django.http.HttpResponse.headers` została zmieniona na `_headers` a `HttpResponse` obsługuje od teraz bezpośrednie sprawdzanie występowania kluczy. Używaj więc `if header in response:` zamiast `if header in response.headers:`.

### Relacje generyczne

#### Relacje generyczne zostały przeniesione poza core

Klasy relacji generycznych – `GenericForeignKey` i `GenericRelation` – zostały przeniesione do modułu `django.contrib.contenttypes`.

### Testowanie

#### `django.test.Client.login()` został zmieniony

Old (0.96):

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

New (1.0):

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

### Komendy zarządzania

#### Uruchamianie komend zarządzania z Twojego kodu

`django.core.management` został znacznie zrefaktorowany.

Calls to management services in your code now need to use `call_command`. For example, if you have some test code that calls flush and load_data:

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

…you’ll need to change this code to read:

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

#### Subcommands must now precede options

`django-admin.py` and `manage.py` now require subcommands to precede options. So:

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

…no longer works and should be changed to:

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

### Syndykacja treści

#### `Feed.__init__` has changed

The `__init__()` method of the syndication framework’s `Feed` class now takes an `HttpRequest` object as its second parameter, instead of the feed’s URL. This allows the syndication framework to work without requiring the sites framework. This only affects code that subclasses `Feed` and overrides the `__init__()` method, and code that calls `Feed.__init__()` directly.

### Data structures

#### `SortedDictFromList` is gone

`django.newforms.forms.SortedDictFromList` was removed. `django.utils.datastructures.SortedDict` can now be instantiated with a sequence of tuples.

To update your code:

1. Use `django.utils.datastructures.SortedDict` wherever you were using `django.newforms.forms.SortedDictFromList`.
2. Because `django.utils.datastructures.SortedDict.copy` doesn’t return a deepcopy as `SortedDictFromList.copy()` did, you will need to update your code if you were relying on a deepcopy. Do this by using `copy.deepcopy` directly.

### Database backend functions

#### Database backend functions have been renamed

Almost all of the database backend-level functions have been renamed and/or relocated. None of these were documented, but you’ll need to change your code if you’re using any of these functions, all of which are in `django.db`:

Old (0.96) | New (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`