---
title: "Menghubungkan aplikasi anda dari Django 0.96 ke 1.0"
version: 1.9
locale: id
source: https://docs.djangoproject.com/id/1.9/releases/1.0-porting-guide/
canonical: https://djangodocs.dev/id/1.9/releases/1.0-porting-guide/
---
# Menghubungkan aplikasi anda dari Django 0.96 ke 1.0

Django 1.0 memutus kesesuaian dengan 0.96 di beberapa kawasan.

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](#less-common-changes) for a list of a bunch of less-common compatibility issues.

> **See also**
>
> The [1.0 release notes](/id/1.9/releases/1.0/). That document explains the new
> features in 1.0 more deeply; the porting guide is more concerned with
> helping you quickly update your code.

## Perubahan umum

Bagian ini menggambarkan perubahan diantara 0.96 dan 1.0 yang paling pengguna butuhkan untuk dibuat.

### Gunakan 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.

Lihat [Unicode data](/id/1.9/ref/unicode/) untuk rincian penuh.

### Model

Perubahan umum ke berkas model anda:

#### Namai kembali `maxlength` ke `max_length`

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

#### Ganti `__str__` dengan `__unicode__`

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

#### Pindahkan `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](#the-admin), below, for more details about changes to the admin.

#### Pindahkan `core`

Remove the `core` argument from your model fields. It is no longer
necessary, since the equivalent functionality (part of [inline editing](/id/1.9/ref/contrib/admin/#admin-inlines)) is handled differently by the admin interface now. You don't
have to worry about inline editing until you get to [the admin](#the-admin) section,
below. For now, remove all references to `core`.

#### Ganti `class Admin:` dengan `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](#the-admin) below for more details.

> **See also**
>
> A contributor to [djangosnippets](https://www.djangosnippets.org/) has written a script that'll [scan your
> models.py and generate a corresponding admin.py](https://www.djangosnippets.org/snippets/603/).

#### Contoh

DIbawah ini adalah sebuah contoh berkas `models.py` dengan semua perubahan anda ingin buat:

Lama (0.96) `models.py`:

```python
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)
```

Baru (1.0) `models.py`:

```python
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)
```

Baru (1.0) `admin.py`:

```python
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)
```

### 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](#models) above how to replace your `class
Admin` with a `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.

#### Gunakan sintaks seiring yang baru

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

Lama (0.96):

```python
class Parent(models.Model):
    ...

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

Baru (1.0):

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

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

admin.site.register(Parent, ParentAdmin)
```

Lihat [Obyek InlineModelAdmin](/id/1.9/ref/contrib/admin/#admin-inlines) untuk rinci.

#### Sederhanakan `fields`, atau gunakan `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.

Lama (0.96):

```python
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'}),
        )
```

Baru (1.0):

```python
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'}),
    )
```

> **See also**
>
> - More detailed information about the changes and the reasons behind them
>   can be found on the [NewformsAdminBranch wiki page](https://code.djangoproject.com/wiki/NewformsAdminBranch)
> - The new admin comes with a ton of new features; you can read about them in
>   the [admin documentation](/id/1.9/ref/contrib/admin/).

### URL

#### Perbaharui akar `urls.py` anda.

Jika anda menggunakan situs admin, anda butuh memperbaharui akar `urls.py` anda.

Lama (0.96) `urls.py`:

```python
from django.conf.urls.defaults import *

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

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

Baru (1.0) `urls.py`:

```python
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 ...
)
```

### View

#### Gunakan `django.forms` sebagai gantinya `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.

Lama:

```python
from django import newforms as forms
```

Baru:

```python
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](/id/1.9/topics/forms/)

#### Menangani berkas terunggah menggunakan API baru

Replace use of uploaded files -- that is, entries in `request.FILES` -- as
simple dictionaries with the new
[`UploadedFile`](/id/1.9/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile). The old dictionary
syntax no longer works.

Jadi, dalam tampilan seperti:

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

...anda butuh membuat perubahan berikut:

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

#### Bekerja dengan bidang berkas menggunakan API baru

The internal implementation of [`django.db.models.FileField`](/id/1.9/ref/models/fields/#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`](/id/1.9/ref/models/fields/#django.db.models.FileField) is called `myfile`:

| Lama (0.96) | Baru (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`](/id/1.9/ref/models/fields/#django.db.models.ImageField) fields. More details can be found in the
[model API](/id/1.9/ref/models/fields/) documentation.

#### Gunakan `Paginator` daripada `ObjectPaginator`

The `ObjectPaginator` in 0.96 has been removed and replaced with an improved
version, [`django.core.paginator.Paginator`](/id/1.9/topics/pagination/#django.core.paginator.Paginator).

### Templat

#### 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](/id/1.9/ref/templates/language/#automatic-html-escaping).

To disable auto-escaping for an individual variable, use the [`safe`](/id/1.9/ref/templates/builtins/#std-templatefilter-safe)
filter:

```html+django
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`](/id/1.9/ref/templates/builtins/#std-templatetag-autoescape) tag:

```html+django
{% 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.

### Sinyal

- Add `**kwargs` to any registered signal handlers.
- Connect, disconnect, and send signals via methods on the
  [`Signal`](/id/1.9/topics/signals/#django.dispatch.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`](/id/1.9/topics/signals/#django.dispatch.Signal) instead of anonymous objects.

Berikut rekap dari perubahan kode yang perlu anda lakukan:

| Lama (0.96) | Baru (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)` |

### Komentar

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.

### Tag templat

#### Etiket [`spaceless`](/id/1.9/ref/templates/builtins/#std-templatetag-spaceless)

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

### Rasa lokal

#### Rasa lokal U.S

`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.

### Sesi

#### Mendapatkan kunci sesi baru

`SessionBase.get_new_session_key()` telah dinamai kembali menjadi `_get_new_session_key()`. `get_new_session_object()` tidak lagi ada.

### Perlengkapan

#### Memuat sebuah baris yang tidak memanggil `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.

### Pengaturan

#### Pengecualian terbaik

The old [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError) has split into an
[`ImportError`](https://docs.python.org/3/library/exceptions.html#ImportError) when Django fails to find the settings module
and a [`RuntimeError`](https://docs.python.org/3/library/exceptions.html#RuntimeError) when you try to reconfigure settings
after having already used them.

#### [`LOGIN_URL`](/id/1.9/ref/settings/#std-setting-LOGIN_URL) telah dipindahkan

The [`LOGIN_URL`](/id/1.9/ref/settings/#std-setting-LOGIN_URL) constant moved from `django.contrib.auth` into the
`settings` module. Instead of using `from django.contrib.auth import
LOGIN_URL` refer to [`settings.LOGIN_URL`](/id/1.9/ref/settings/#std-setting-LOGIN_URL).

#### Kebiasaan [`APPEND_SLASH`](/id/1.9/ref/settings/#std-setting-APPEND_SLASH) telah diperbaharui

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`](/id/1.9/ref/settings/#std-setting-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.

For most people, this won't require any changes. Some people, though, have URL
patterns that look like this:

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

Previously, those patterns would have been redirected to have a trailing
slash. If you always want a slash on such URLs, rewrite the pattern as:

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

### Perubahan model kecil

#### Pengecualian berbeda dari `get()`

Managers now return a [`MultipleObjectsReturned`](/id/1.9/ref/exceptions/#django.core.exceptions.MultipleObjectsReturned)
exception instead of [`AssertionError`](https://docs.python.org/3/library/exceptions.html#AssertionError):

Lama (0.96):

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

Baru (1.0):

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

#### `LazyDate` has been fired

The `LazyDate` helper class no longer exists.

Default field values and query arguments can both be callable objects, so
instances of `LazyDate` can be replaced with a reference to `datetime.datetime.now`:

Lama (0.96):

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

Baru (1.0):

```python
import datetime

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

#### `DecimalField` is new, and `FloatField` is now a proper float

Lama (0.96):

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

Baru (1.0):

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

If you forget to make this change, you will see errors about `FloatField`
not taking a `max_digits` attribute in `__init__`, because the new
`FloatField` takes no precision-related arguments.

If you're using MySQL or PostgreSQL, no further changes are needed. The
database column types for `DecimalField` are the same as for the old
`FloatField`.

If you're using SQLite, you need to force the database to view the
appropriate columns as decimal types, rather than floats. To do this, you'll
need to reload your data. Do this after you have made the change to using
`DecimalField` in your code and updated the Django code.

> **Warning**
>
> **Sokong basisdata anda dahulu!**
>
> For SQLite, this means making a copy of the single file that stores the
> database (the name of that file is the `DATABASE_NAME` in your
> settings.py file).

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

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

Catatan:

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, of course.
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.

### Internasionalisasi

#### [`django.views.i18n.set_language()`](/id/1.9/topics/i18n/translation/#django.views.i18n.set_language) sekarang membutuhkan permintaan POST

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:

```python
from django.utils.translation import ugettext as _
```

### Obyek HTTP request/response

#### Akses kamus ke `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.

#### Mengakses kepala `HTTPResponse`

`django.http.HttpResponse.headers` has been renamed to `_headers` and
[`HttpResponse`](/id/1.9/ref/request-response/#django.http.HttpResponse) now supports containment checking directly.
So use `if header in response:` instead of `if header in response.headers:`.

### Hubungan umum

#### Generic relations have been moved out of core

The generic relation classes -- `GenericForeignKey` and `GenericRelation`
-- have moved into the [`django.contrib.contenttypes`](/id/1.9/ref/contrib/contenttypes/#module-django.contrib.contenttypes) module.

### Pengujian

#### meth:django.test.Client.login telah berubah

Lama (0.96):

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

Baru (1.0):

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

### Pengelolaan perintah

#### Menjalankan pengelolaan perintah dari kode anda

[`django.core.management`](/id/1.9/howto/custom-management-commands/#module-django.core.management) has been greatly refactored.

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:

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

...anda akan butuh merubah kdoe ini untuk dibaca:

```python
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:

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

...tidak lagi bekerja dan harus dirubah menjadi:

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

### Kongsi

#### `Feed.__init__` telah berubah

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.

### Struktur data

#### SortedDictFromList\` telah pergi

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

Untuk memperbaharui kode anda:

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.

### Fungsi basisdata backend

#### Fungsi basisdata backend telah diubah namanya

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`](/id/1.9/topics/db/#module-django.db):

| Lama (0.96) | Baru (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` |
