Menghubungkan aplikasi anda dari Django 0.96 ke 1.0¶
Django 1.0 memutus kesesuaian dengan 0.96 di beberapa kawasan.
Panduan ini akan membantu anda menghubungkan proyek 0.96 dan apliaksi ke 1.0. Bagian pertama dari dokumen ini termasuk perubahan umum dibutuhkan untuk berjalan dengan 1.0. Jika setelah melalui bagian pertama kode anda masih rusak, periksa bagian Less-common Changes untuk daftar ikatan masalah kesesuaian yang kurang umum.
lihat juga
1.0 release notes. Dokumen itu menjelaskan fitur-fitur baru di 1.0 lebih dalam; panduan menghubungkan lebih diperhatikan dengan bantuan anda dengan cepat memperbaharui kode anda.
Perubahan umum¶
Bagian ini menggambarkan perubahan diantara 0.96 dan 1.0 yang paling pengguna butuhkan untuk dibuat.
Gunakan Unicode¶
Merubah harfiah deretan karakter ('foo') menjadi harfiah Unicode (u'foo'). Django sekarang menggunakan deretan karakter Unicode seluruhnya. Di kebanyakan tempat, deretan karakter mentah akan lanjut bekerja, tetapi memperbaharui untuk menggunakan harfiah Unicode akan mencegah pengaburan beberapa masalah.
Lihat Data Unicode untuk rincian penuh.
Model¶
Perubahan umum ke berkas model anda:
Namai kembali maxlength ke max_length¶
Namai kembali argumen maxlength anda ke max_length (ini dirubah agar selaras dengan bidang-bidang formulir):
Ganti __str__ dengan __unicode__¶
Ganti fungsi __str__ model anda dengan metode __unicode__, dan pastikan anda use Unicode (u'foo') di metode itu.
Pindahkan prepopulated_from¶
Pindahkan argumen prepopulated_from pada bidang model. Itu tidak lagi sah dan telah dipindahkan ke kelas ModelAdmin di admin.py. Lihat the admin, dibawah ini, untuk rincian lebih tentang dirubah ke admin.
Pindahkan core¶
Pindahkan argumen core dari bidang model anda. itu tidak lagi dibutuhkan, sejak kegunaan yang setara (bagian dari inline editing) ditangani dengan berbeda oleh antarmuka admin sekarang. Anda tidak harus khawatir tentang penyuntingan berderet sampai anda menuju bagian the admin, dibawah. Untuk sekarang, pindahkan semua acuan ke core.
Ganti class Admin: dengan admin.py¶
Pindahkan semua pernyataan class Admin sebelah dalam dari model anda. Mereka tidak merusak apapun jika anda meninggalkan mereka, tetapi mereka juga tidak akan melakukan apapun. Untuk mendaftarkan aplikasi dengan admin anda akan pindahkan pernyataan itu ke berkas admin.py; lihat the admin dibawah untuk lebih rinci.
lihat juga
Seorang penyumbang pada djangosnippets telah menuli skembali sebuah tulisan yang akan scan your models.py and generate a corresponding admin.py.
Contoh¶
DIbawah ini adalah sebuah contoh berkas models.py dengan semua perubahan anda ingin buat:
Lama (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)
Baru (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)
Baru (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)
Admin¶
Satu dari perubahan terbesar di 1.0 adalah admin baru. Antarmuka administratif Django (django.contrib.admin) telah sepenuhnya di refaktor; pengertian admin sekarang sepenuhnya dipisahkan dari pengertian model, kerangka kerja telah ditulis kembali untuk menggunakan pustaka penanganan formulir baru Django dan dirancang kembali dengan perpanjangan dan penyesuaian dalam pikiran.
Sebenarnya, ini berarti anda akan butuh menulis kembali semua pernyataan class Admin anda. Anda telah melihat di models diatas bagaimana mengganti class Admin anda dengan sebuah panggilan admin.site.register() dalam sebuah berkas admin.py. Dibawah ini adalah beberapa lebih rinci pada bagimana menulis kembali pernyataan Admin itu kedalam sintaksis baru.
Gunakan sintaksis berderet yang baru¶
Pilihan edit_inline baru semua telah dipindahkan ke admin.py. Ini adalah contoh:
Lama (0.96):
class Parent(models.Model):
...
class Child(models.Model):
parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)
Baru (1.0):
class ChildInline(admin.StackedInline):
model = Child
extra = 3
class ParentAdmin(admin.ModelAdmin):
model = Parent
inlines = [ChildInline]
admin.site.register(Parent, ParentAdmin)
Lihat Obyek InlineModelAdmin untuk rinci.
Sederhanakan fields, atau gunakan fieldsets¶
Sintaksis fields lama sangat membingungkan, dan telah disederhanakan. Sintaksis lama masih bekerja, tetapi anda akan butuh menggunakan fieldsets sebagai gantinya.
Lama (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'}),
)
Baru (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'}),
)
lihat juga
- Informasi lebih rinci mengenai perubahan dan alasan dibelakang mereka dapat ditemukan pada NewformsAdminBranch wiki page
- Admin baru datang dengan satu ton fitur baru; anda dapat membaca tentang mereka di admin documentation.
URL¶
Perbaharui akar urls.py anda.¶
Jika anda menggunakan situs admin, anda butuh memperbaharui akar urls.py anda.
Lama (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 ...
)
Baru (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 ...
)
View¶
Gunakan django.forms sebagai gantinya newforms¶
Ganti django.newforms dengan django.forms -- Django 1.0 dinamai kembali modul newforms (diperkenalkan di 0.96) untuk forms lama kosong. Modul oldforms juga dipindahkan.
Jika anda sudah menggunakan pustaka newforms, dan anda menggunakan anjuran kami sintaksis pernyataan import, semua anda harus lakukan adalah merubah pernyataan impor anda.
Lama:
from django import newforms as forms
Baru:
from django import forms
Jika anda sedang menggunakan sistem formulir lama (dahulu dikenal sebagai django.forms dan django.oldforms), anda akan harus menuli skembali formulir anda. Tempat bagus untuk memulai adalah forms documentation
Menangani berkas terunggah menggunakan API baru¶
Rubah penggunaan berkas-berkas terunggah -- yaitu, masukan di request.FILES -- sebagai kamus sederhana dengan UploadedFile baru. Sintaksis kamus lama tidak lagi bekerja.
Jadi, dalam tampilan seperti:
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¶
Penerapan internal dari django.db.models.FileField telah berubah. Hasil nampak dari ini adalah bahwa cara anda mengakses atribut khusus (URL, berkas nama, ukuran gambar, dll.) dari bidang model ini telah berubah. Anda akan butuh membuat perubahan berikut, menganggap FileField model anda dipanggil 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 |
Catat bahwa atribut width dan height hanya masuk akal untuk bidang ImageField. Rincian lebih dapat ditemukan di dokumentasi model API.
Gunakan Paginator daripada ObjectPaginator¶
ObjectPaginator di 0.96 telah dipindahkan dan diganti dengan versi diperbaiki, django.core.paginator.Paginator.
Templat¶
Belajar mencintai pelolosan otomatis¶
Secara awal, sistem cetakan sekarang otomatis meloloskan HTML keluaran setiap variabel. Untuk mempelajari lebih, lihat Pelolosan HTML otomatis.
Untuk meniadakan pelolosan otomatis untuk variabel tersendiri, gunakan safe filter:
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
Untuk meniadakan pelolosan otomatis untuk keseluruhan cetakan, bungkus cetakan (atau cukup bagian tertentu dari cetakan) di etiket autoescape:
{% autoescape off %}
... unescaped template content here ...
{% endautoescape %}
Perubahan kurang umum¶
Perubahan berikut lebih kecil, lebih perubahan lokal. Mereka hanya berpengaruh lebih pengguna lanjutan, tetapi itu mungkin bernilai baik membaca melalui daftar dan memeriksa kode anda untuk hal-hal ini.
Sinyal¶
- Tambah
**kwargspada setiap penangan sinyal terdaftar. - Hubungkan, putuskan, dan kirim sinyal melalui metode pada obyek
Signaldaripada melalui modul metode didjango.dispatch.dispatcher. - Pindahkan tiap penggunaan pilihan pengirim
AnonymousdanAny; mereka tidak lagi ada. Anda masih dapat menerima sinyal dikirim oleh pengirim dengan menggunakansender=None - Buat sinyal penyesuaian apa saja anda telah nyatakan kedalam instance dari
django.dispatch.Signalsebagai ganti dari obyek anonim.
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¶
Jika anda menggunakan aplikasi django.contrib.comments Django 0.96, anda akan btuuh meningkatkan ke aplikasi komentar baru diperkenalkan di 1.0. Lihat panduan peningkatan untuk rincian.
Tag templat¶
Rasa lokal¶
Rasa lokal U.S¶
django.contrib.localflavor.usa telah dinamai kembali ke django.contrib.localflavor.us. Perubahan ini dibuat untuk mencocokan penamaan skema dari rasa lokal lainnya. Untuk memindahkan kode anda, anda yang butuh lakukan adalah merubah impor.
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()¶
Sebelumnya, memuat sebuah baris secara otomatis menjalankan metode save() model. Ini bukan lagi kasus, jadi tiap bidang (sebagai contoh: timestamp) yang dikumpulkan otomatis oleh save() sekarang butuh nilai eksplisit di tiap perlengkapan tetap.
Pengaturan¶
Pengecualian terbaik¶
EnvironmentError lama telah dipisah menjadi ImportError ketika Django gagal menemukan modul pengaturan dan RuntimeError ketika anda mencoba mengkonfigurasi kembali pengaturan setelah selesai menggunakan mereka.
LOGIN_URL telah dipindahkan¶
Ketetapan LOGIN_URL dipindah dari django.contrib.auth kedalam modul settings. Daripada menggunakan from django.contrib.auth import LOGIN_URL mengacu pada settings.LOGIN_URL.
Perilaku APPEND_SLASH telah diperbaharui¶
Di 0.96, jika sebuah URL tidak berakhir di garis miring atau mempunyai titik di akhir komponen dari jalurnya, dan APPEND_SLASH adalah True, Django akan mengalihkan ke URL sama, tetapi dengan tanda miring ditambahkan pada akhir. Sekarang, Django memeriksa apakah pola tanpa ekor garis miring akan cocok oleh sesuatu di pola URL anda. Jika demikian, tidak ada pengalihan, karena itu dianggap anda sengaja ingin menangkap pola itu.
Untuk kebanyakan orang, ini tidak akan membutuhkan perubahan. Beberapa orang, meskipun, mempunyai pola URL yang terlihat seperti ini:
r'/some_prefix/(.*)$'
Sebelumnya, pola itu akan dialihkan untuk mempunyai sebuah ekor garis miring. Jika anda selalu ingin garis miring pada URL itu, tulis kembali pola sebagai:
r'/some_prefix/(.*/)$'
Perubahan model kecil¶
Pengecualian berbeda dari get()¶
Pengelola sekarang mengembalikan pengecualian MultipleObjectsReturned daripada AssertionError:
Lama (0.96):
try:
Model.objects.get(...)
except AssertionError:
handle_the_error()
Baru (1.0):
try:
Model.objects.get(...)
except Model.MultipleObjectsReturned:
handle_the_error()
LazyDate telah dinyalakan¶
Kelas pembantu LazyDate tidak lagi ada.
Nilai bidang awalan dan permintaan argumen keduanya obyek callable, jadi instance dari LazyDate dapat diganti dengan acuan pada datetime.datetime.now:
Lama (0.96):
class Article(models.Model):
title = models.CharField(maxlength=100)
published = models.DateField(default=LazyDate())
Baru (1.0):
import datetime
class Article(models.Model):
title = models.CharField(max_length=100)
published = models.DateField(default=datetime.datetime.now)
DecimalField adalah baru, dan FloatField sekarang float tepat.¶
Lama (0.96):
class MyModel(models.Model):
field_name = models.FloatField(max_digits=10, decimal_places=3)
...
Baru (1.0):
class MyModel(models.Model):
field_name = models.DecimalField(max_digits=10, decimal_places=3)
...
Jika anda lupa membuat perubahan ini, anda akan melihat kesalahan tentang FloatField bukan mengambil atribut max_digits di __init__, karena FloatField baru mengambil argumen terkait tidak teliti.
Jika anda sedang menggunakan MySQL atau PostgreSQL, tidak dibtuuhkan perubahan lebih lanjut. Jenis kolom basisdata untuk DecimalField adalah sama untuk FloatField lama.
Jika anda menggunakan SQLite, anda butuh memaksa basisdata melihat kolom yang sesuai sebagai jenis desimal, daripada float. untuk melakukan ini, anda akan butuh memuat kembali data anda. Lakukam ini setelah anda membuat perubahan untuk menggunakan DecimalField di kode anda dan kode Django diperbaharui.
Peringatan
Sokong basisdata anda dahulu!
Untuk SQLite, ini berarti membuat sebuah salinan dari berkas tunggal yang menyimpan basisdata (nama dari berkas itu adalah DATABASE_NAME di berkas settings.py anda).
Untuk meningkatkan setiap aplikasi untuk menggunakan sebuah DecimalField, anda dapat melakukan berikut, mengganti <app> di kode dibawah ini dengan setiap nama aplikasi:
$ ./manage.py dumpdata --format=xml <app> > data-dump.xml
$ ./manage.py reset <app>
$ ./manage.py loaddata data-dump.xml
Catatan:
- Itu sangat penting bahwa anda mengingat untuk menggunakan bentuk XML dalam langkah pertama dari pengolahan ini. Kami sedang menggunakan fitur dari data buangan XML yang membuat belokan float ke desimal dengan SQLite memungkinkan.
- Di langkah kedua anda akan diminta menegaskan bahwa anda siap kehilangan data untuk aplikasi di pertanyaan. Katakan ya; kami akan menyimpan kembali data ini di langkah ketiga, tentu saja.
DecimalFieldtidak digunakan di tiap aplikasi yang dibekali dengan Django sebelum perubahan ini dibuat, jadi anda tidak butuh khawatir tentang melakukan prosedur ini untuk tiap model Django standar.
Jika sesuatu berjalan salah di pengolahan diatas, cukup salin berkas basisdata sokongan anda terhadap berkas asli dan mulai kembali.
Internasionalisasi¶
django.views.i18n.set_language() sekarang membutuhkan permintaan POST¶
Sebelumnya, permintaan GET telah digunakan. Perilaku lama berarti bahwa keadaan (lokal digunakan untuk menampilkan situs) dapat berubah dengan permintaan GET, yaitu terhadap anjuran spesifikasi HTTP. Kode memanggil tampilan ini harus memastikan bahwa permintaan POST sekaragn dibuat, sebagai gantinya GET. Ini berarti anda tidak dapat lagi menggunakan tautan mengakses tampilan, tetapi harus menggunakan pengajuan formulir dari sejenis (sebagai contoh tombol).
_() tidak lagi siap pakai¶
_() (obyek callable yang namanya adalah garis bawah tunggal) tidak lagi monkeypatch kedalam siap pakai -- yaitu, itu tidak lagi tersedia secara ajaib di setiap modul.
Jika anda sebelumnya bergantung pada _() selalu menjadi hadir, anda harus sekarang secara eksplisit mengimpor ugettext atau ugettext_lazy, jika sesuai, dan namai itu menjadi _ anda sendiri:
from django.utils.translation import ugettext as _
Obyek HTTP request/response¶
Akses kamus ke HttpRequest¶
Obyek HttpRequest tidak lagi langsung mendukung akses gaya kamus; sebelumnya, kedua data GET dan POST langsung tersedia pada obyek HttpRequest (sebagai contoh, anda dapat memeriksa untuk potongan dari formulir data dengan menggunakan if 'some_form_key' in request atau dengan membaca request['some_form_key']. Ini tidak lagi didukung; jika anda butuh akses untuk mengkombinasikan data GET dan POST, gunakan request.REQUEST sebagai gantinya.
Itu sangat disarankan, bagaimanapun, bahwa anda selalu secara eksplisit mencari di kamus yang sesuai untuk jenis dari permintaan anda harapkan untuk menerima (request.GET or request.POST); bergantung pada gabungan kamus request.REQUEST dapat menutup data datang asli.
Mengakses kepala HTTPResponse¶
django.http.HttpResponse.headers telah dinamai kembali ke _headers dan HttpResponse sekarang mendukung penahanan pemeriksaan secara langsung. Jadi gunakan if header in response: daripada if header in response.headers:.
Hubungan umum¶
Hubungan umum telah dipindahkan keluar dari inti¶
Kelas-kelas hubungan umum -- GenericForeignKey dan GenericRelation -- telah dipindahkan kedalam modul django.contrib.contenttypes.
Pengujian¶
meth:django.test.Client.login telah berubah¶
Lama (0.96):
from django.test import Client
c = Client()
c.login('/path/to/login','myuser','mypassword')
Baru (1.0):
# ... same as above, but then:
c.login(username='myuser', password='mypassword')
Pengelolaan perintah¶
Menjalankan pengelolaan perintah dari kode anda¶
django.core.management telah direfaktor.
Panggilan pada pengelolaan pelayanan di kode anda sekarang butuh untuk menggunakan call_command. Sebagai contoh, jika anda mempunyai beberapa percobaan yang memanggil flush dan load_data:
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:
from django.core import management
management.call_command('flush', verbosity=0, interactive=False)
management.call_command('loaddata', 'test_data', verbosity=0)
Sub perintah sekarang harus mendahulukan pilihan¶
django-admin.py dan manage.py sekarang membutuhkan sub perintah untuk mendahulukan pilihan. Jadi:
$ django-admin.py --settings=foo.bar runserver
...tidak lagi bekerja dan harus dirubah menjadi:
$ django-admin.py runserver --settings=foo.bar
Kongsi¶
Feed.__init__ telah berubah¶
metode __init__() dari kongsi kelas Feed kerangka kerja sekarang mengambil sebuah obyek HttpRequest sebagai parameter keduanya, daripada URL umpan. Ini mengizinkan kongsi kerangka kerja untuk bekerja tanpa membutuhkan kerangka kerja situs. Ini hanya mempengaruhi kode yang subkelas Feed dan menimpa metode __init__(), dan kode yang memanggil Feed.__init__() secara langsung.
Struktur data¶
SortedDictFromList` telah pergi¶
django.newforms.forms.SortedDictFromList telah dipindahkan. django.utils.datastructures.SortedDict sekarang dapat membuat obyek dengan urutan dari tuple-tuple.
Untuk memperbaharui kode anda:
- Gunakan
django.utils.datastructures.SortedDictdimanapun anda menggunakandjango.newforms.forms.SortedDictFromList. - Karena
django.utils.datastructures.SortedDict.copytidak mengemblikan salinan dalam sebagaiSortedDictFromList.copy()lakukan, anda akan butuh memperbaharui kode anda jika anda bergantung pada saliann dalam. Lakukan ini dengan menggunakancopy.deepcopysecara langsung.
Fungsi basisdata backend¶
Fungsi basisdata backend telah diubah namanya¶
Hampir semua dari fungsi tingkatan backend basisdata telah dinamai kembali dan/atau ditempatkan kembali. Tidak ada dari ini didokumentasikan, tetapi anda akan butuh merubah kode anda jika anda sedang menggunakan tiap fungsi ini, semua dari yang berada di 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 |