Ze względu na młody wiek frameworka (sprzed wydania 1.0) twórcy postanowili nie utrzymywać pełnej wstecznej zgodności, przekładając nad to rozwój Django. W porównaniu z wersją 0.96 pojawiło się szereg wstecznie niezgodnych zmian. Osoby używające Django-SVN zapewne znają większą, poza np. tymi wprowadzonymi niedawno jak newforms-admin. Począwszy od wersji 1.0 wsteczna zgodność będzie zachowywana najlepiej jak to możliwe. Szczegółowa lista zmian na
wiki Django.
Tag
{{ spaceless }} usuwa wszystkie spacje pomiędzy tagami HTML, a nie jak wcześniej zachowując jedną spację z wielu.
Taki kod
{% spaceless %}
<p>
<a href="foo/">Foo</a>
</p>
{% endspaceless %}
W starszej wersji dałby wynik
<p> <a href="foo/">Foo</a> </p>
Po zmiana wynik będzie następujący:
<p><a href="foo/">Foo</a></p>
Pomocnik
LazyDate został usunięty. Zastąpić można go obiektem
datetime.now. Stary kod np:
class Article(models.Model):
title = models.CharField(maxlength=100)
published = models.DateField(default=LazyDate())
Można zmodyfikować do postaci:
from datetime import datetime
class Article(models.Model):
title = models.CharField(maxlength=100)
published = models.DateField(default=datetime.now)
W rewizji 5042 wprowadzono małą zmianę w obsłudze kolumn
CHAR(n). Zmienia to nieco wynikowe tabele wygenerowane przez Django, lecz nie wymaga zmian w kodzie.
W r5072 LOGIN_URL z komponentu autoryzacji został przeniesiony do ustawień umożliwiając elastyczniejszą zmianę. Stary kod w postaci:
from django.contrib.auth import LOGIN_URL
Powinien zostać zmieniony by odpowiadać
settings.LOGIN_URL.
django.test.Client.login() obecnie nie wykorzystuje specyficznych szablonów i formularzy logowania, lecz bezpośrednio próbuje tworzy odpowiednie ciasteczka i obiekty sesji umożliwiając wykorzystanie metody z dowolnym systemem logowania. Stary kod w postaci
c = Client()
c.login('/path/to/login','myuser','mypassword')
Należy zastąpić
c = Client()
c.login(username='myuser', password='mypassword')
GenericRelation i GenericForeignKey zostały przeniesione do django.contrib.contenttypes, jako że bez tej aplikacji nie będą działały.
Od rewizji 5237 sprawdzone (cleaned) dane z formularzy dostępne są przez cleaned_data.
Ze względu na różne formy przesyłania plików usunięto pomocnika w Test Client odpowiadającego typowi FileField.
Zmieniono nazwę typu danych "FloatField" na "DecimalField", a także reprezentowanie jej w Pythonie jako typ Decimal, a nie Float (co wcześniej powodowało utratę dokładności ze względu na zaokrąglanie). W modelach należy zmienić nazwę pola. Wprowadzono także typ "FloatField" przechowujące dane jako Float.
Uwaga: w przypadku baz SQLite należy wymusić wyświetlanie danych w typie Decimal, a nie Float. Zrób kopię bazy danych (skopiuj plik) i wykonaj operacje:
./manage.py dumpdata --format=xml nazwa_aplikacji > data-dump.xml
./manage.py reset nazwa_aplikacji
./manage.py loaddata data-dump.xml
W celu zwiększenia szybkości działania frameworka reguły mapowania URLi są obecnie keszowane. Po ich zmianie konieczny jest restart Django.
W rewizji 5609 dodano kod z UnicodeBranch odpowiedzialny za obsługę unikodu w Django. W przypadku danych nie-ASCII będzie powodowało to problemy. Opis zapalnych miejsc opisano
na wiki Django. W skrócie:
- Modele muszą mieć metodę __unicode__ (jaks __str__)
- Nie należy stosować str(), a unicode()
- Napisy (np etykiety formularzy, pól modeli) muszą być unikodem:
stare = '%s tekst' % self.cośtam
nowe = u'%s tekst' % self.cośtam
- Pomocne może być też ustawienie domyślnego kodowania Pythona na unikod tworząc plik sitecustomize.py w katalogu z instalacją Pythona, o kodzie:
import sys
sys.setdefaultencoding('utf-8')
Metoda __init__ klasy Feed jako drugi argument może przyjąć obiekt HttpRequest, a nie URL feeda, co umożliwia wykorzystanie klasy bez komponentu Sites. Zmiana wpłynie jedynie na klasy dziedziczące klasę Feed, lub kod bezpośrednio wywołujący __init__().
Ujednolicając kodowanie stosowane w Django, a także przez tłumaczy operujących na plikach gettexta wybrano kodowanie UTF-8 jako jedyne dla plików *po.
Parametr `interactive` umożliwia dodanie testów do skryptów budujących, w których interaktywne pytania w czasie testów nie są możliwe do obsłużenia.
Pierwszym argumentem "run_tests" jest obecnie lista etykiet testów, a nie lista aplikacji, których testy mają zostać wykonane. Zmiana ta wpłynie na osoby używające zmodyfikowanych test_runnerów.
Dodanie `FileField` i `ImageField` do newforms wymusiło drobne zmiany obsługi danych (łączenia). Zmiana ta nie będzie miała wpływu na większość użytkowników.
By umożliwić dodawanie innych poleceń, a także by odchudzić duży plik dokonano kilku zmian w management.py. Zmianie uległo wywoływanie poleceń z np:
>>> from django.core import management
>>> management.flush(verbosity=0, interactive=False)
>>> management.load_data(['test_data'], verbosity=0)
Do postaci:
>>> from django.core import management
>>> management.call_command('flush', verbosity=0, interactive=False)
>>> management.call_command('loaddata', 'test_data', verbosity=0)
Wewnątrz bibliotek ORMa obsługujących różne bazy danych nastąpiło szereg zmian, przez co większość wewnętrznych funkcji została przeniesiona lub ich nazwa została zmieniona. Funkcje te nie są udokumentowane i zmiany wymaga jedynie specyficzny kod, których ich używał bezpośrednio.
Ujednolicając zachowanie generycznych widoków powiązanych z datą generyczny widok archive_year nie sortuje już wyników samodzielnie.
Opcje takie jak --settings muszą być podane po poleceniach takich jak runserver. Np:
django-admin.py --settings=foo.bar runserver
Musi zostać zmodyfikowane do postaci:
django-admin.py runserver --settings=foo.bar
Widok
set_language() został zmieniony tak by przyjmować tylko żądania POST (a nie GET jak wcześniej), gdyż zmiana ustawień za pomocą żądania GET nie jest zalecana przez specyfikację HTTP.
Tag load obsługuje ścieżki zawierające kropki (w stylu Pythona):
Będzie próbowało załadować "foo/bar.py"
Od rewizji 6568 należy samemu zaimportować odpowiednią funkcję gettexta przeznaczoną do obsługi fraz do tłumaczenia, np:
from django.utils.translation import ugettext as _
Ze względu na obecność
django.utils.datastructures.SortedDict usunięta została klasa
django.newforms.forms.SortedDictFromList.
Dane (zmienne) przekazane do szablonów będą miały enkodowane tagi HTML. By uniknąć enkodowania można użyć filtra |save lub autoescape:
{% autoescape off %}
{{ zmienna }}
{% endautoescape %}
{{ zmienna|save }}
Usunięto kilka nieużywanych funkcji z komponentu obsługi sesji.
Zmianie uległy typy wyjątków generowanych w przypadku problemu z ustawieniami (brak pliku określonego przez DJANGO_SETTINGS_MODULE itd)
Zmieniono domyślną wartość allow_empty na True dla
archive_index() i
object_list()
Jeżeli
QuerySet.get() zwróci więcej niż jeden rekord zostanie wyrzucony wyjątek `MultipleObjectsReturned`.
Jeżeli APPEND_SLASH ustawione jest na True, a Django dostanie URL nie kończący się ukośnikiem / sprawdzi czy może dopasować taki odnośnik zanim przekieruje na odnośnik z zamykającym ukośnikiem.
Przed:
# formularz dodania
obj = MyObj()
form = MyForm(obj)
# formularz edycji
obj = MyObj.objects.get(pk=1)
form = MyForm(obj)
Obecnie:
# formularz dodania
form = MyForm()
# formularz edycji
obj = MyObj.objects.get(pk=1)
form = MyForm(instance=obj)
Jeżeli tag "extends" jest używany to musi znaleźć się przed innymi tagami.
Sterownik do ado_mssql został usunięty ze względu na brak obsługi. Jako alternatywę można użyć http://code.google.com/p/django-mssql/ lub http://code.google.com/p/django-pyodbc/.
W rewizji 7477 dodano kod z gałęzi Queryset-refactor, co zmienia nieco korzystanie z ORM, np. relacji OneToOne. Zmiany opisane są w dokumentacji relacji/modeli.
Zwiększono restrykcje dotyczące obiektów przypisywanych do ForeignKey i OneToOne.
Usunięto pole OrderingField, które pojawiło się w gałęzi MagicRemoval, lecz nigdy nie zostało wykorzystane.
Dla pól BooleanField opcja "required=True" oznacza iż pole musi zostać zaznaczone. Jeżeli zaznaczenie pola nie jest wymagane należy dodać
required=False.
Ze względu na duże wykorzystanie tabeli związanej z django.contrib.auth.models.User usunięto domyślne sortowania.
Zmianie uległ sposób przesyłania plików. Przed zmianą request.FILES zawierał dane w słownikach, a obecnie dane dostępne są w odpowiednim obiekcie. Całość zmian opisana jest w dokumentacji
przesyłania plików.
Funkcje pełnione przez make-messages.py zostały przeniesione do django-admin.py:
django-admin.py makemessages -l xx
django-admin.py compilemessages -l xx
Usunięto sterownik dla przestarzałej wersji `MySQLdb`
Usunięto kilka wewnętrznych funcji, w których model był przekazywany bez celu.
Generyczne widoki dodawania/edycji używają newforms.
Wraz z obsługą newforms w Panelu Admina wprowadzono liczne zmiany w funkcjonowaniu i konfiguracji Panelu Admina. Dla urls.py:
# STARE:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^admin/', include('django.contrib.admin.urls')),
)
# NOWE:
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
)
Panel Admina dla danego modelu nie jest już konfigurowany przez podklasę Admin w modelu, lecz przez klasę umieszczoną w admin.py
# STARE:
# models.py
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=100)
class Admin:
pass
# NOWE:
# models.py
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=100)
# admin.py
from django.contrib import admin
from myproject.myapp.models import MyModel
admin.site.register(MyModel)
Wszystkie opcje za wyjątkiem tych wymienionych poniżej nadal obowiązują.
# STARE:
# models.py
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=100)
class Admin:
list_display = ('name',)
# NOWE:
# models.py
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=100)
# admin.py
from django.contrib import admin
from myproject.myapp.models import MyModel
class MyModelAdmin(admin.ModelAdmin):
list_display = ('name',)
admin.site.register(MyModel, MyModelAdmin)
Klasa ModelAdmin może mieć zdefiniowaną metodę queryset:
class BookAdmin(admin.ModelAdmin):
def queryset(self, request):
"""
Filtrowanie po obecnie zalogowanym użytkowniku
"""
return self.model._default_manager.filter(user=request.user)
W klasie ModelAdmin dodano opcję prepopulated_fields, która zastąpiła prepopulate_from z modeli.
# STARE:
class MyModel(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
slug = models.CharField(max_length=60, prepopulate_from=('first_name', 'last_name'))
class Admin:
pass
# NOWE:
class MyModel(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
slug = models.CharField(max_length=60)
from django.contrib import admin
class MyModelAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('first_name', 'last_name')}
admin.site.register(MyModel, MyModelAdmin)
"Fields" jest używane do ustawiania kolejności w formularzu. Obecnie akceptuje jedynie listę pól. "Fieldsets" służy także do ich grupowania. Jeżeli "classes" jest podane w specyfikacji pola, to zwracana wartość musi być zmieniona ze stringa na tuplę stringów:
# STARE:
class MyModelA(models.Model):
class Admin:
fields = ('field1','field2','field3','field4')
class MyModelB(models.Model):
class Admin:
fields = (
('group1', {'fields': ('field1','field2'), 'classes': 'collapse'}),
('group2', {'fields': ('field3','field4'), 'classes': 'collapse wide'}),
)
# NOWE:
class MyModelAdmin(admin.ModelAdmin):
fields = ('field1', 'field2', 'field3', 'field4') # Renaming is optional
class AnotherModelAdmin(admin.ModelAdmin):
fieldsets = (
('group1', {'fields': ('field1','field2'), 'classes': ('collapse',)}),
('group2', {'fields': ('field3','field4'), 'classes': ('collapse', 'wide')}),
)
# STARE:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, edit_inline=models.TABULAR)
title = models.CharField(max_length=100)
# NOWE:
# edit_inline nie jest potrzebne
from django.contrib import admin
class BookInline(admin.TabularInline):
model = Book
extra = 3
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline]
admin.site.register(Author, AuthorAdmin)
Więcej szczegółów znajdziemy w
dokumentacji.
# STARE:
class MyModel(models.Model):
# not relavent, but here for show
field1 = models.CharField(max_length=100)
class Admin:
js = (
"/static/my_code.js",
)
# NOWE:
# in admin.py
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = (
"/static/my_code.js",
)
Jeżeli URLe nie są bezwzględne to dostaną prefiks settings.ADMIN_MEDIA_PREFIX dla newforms-admin (a ogólnie stosowany będzie prefiks settings.MEDIA_URL).
Składnia jest niezależna od modelu
# STARE:
class MyModel(models.Model):
field1 = models.ForeignKey(AnotherModel, raw_id_admin=True)
class Admin:
pass
# NOWE:
class MyModelAdmin(admin.ModelAdmin):
model = MyModel
raw_id_fields = ('field1',)
# STARE:
class MyModel(models.Model):
field1 = models.ForeignKey(AnotherModel, radio_admin=models.VERTICAL)
class Admin:
pass
# NOWE:
class MyModelAdmin(admin.ModelAdmin):
model = MyModel
radio_fields = {'field1': admin.VERTICAL}
# STARE:
class MyModel(models.Model):
field1 = models.ManyToManyField(AnotherModel, filter_interface=models.VERTICAL)
field2 = models.ManyToManyField(YetAnotherModel, filter_interface=models.HORIZONTAL)
# NOWE:
class MyModelAdmin(admin.ModelAdmin):
filter_vertical = ('field1',)
filter_horizontal = ('field2',)
URLe dzielone są przez serwer na dwie części - `SCRIPT_NAME` i `PATH_INFO`. Od rewizji 8015 Django bierze pod uwagę `SCRIPT_NAME` umożliwiając łatwiejsze udostępnianie aplikacji pod różnymi odnośnikami w domenie np. www.strona.pl/django/serwis/*.
Można pozostawić konfigurację bez zmian i wszystko będzie działać, lecz można też zastosować wprowadzone zmiany. Standardowa konfiguracja typu:
<Location "/mysite/">
...
</Location>
powinna wyglądać tak:
<Location "/mysite/">
PythonOption django.root /mysite # Nowa linia
...
</Location>
Opis tej opcji znajduje się w dokumentacji
Django + mod_python. Jej zaletą jest możliwość usunięcia "/mysite" ze wszystkich odnośników stosowanych w kodzie aplikacji.
Wystarczy usunąć prefiks z URLi, nie trzeba zmieniać konfiguracji serwera.
Lighttpd nie przekazuje pełnych danych do ustalenia SCRIPT_NAME. By to rozwiązać należy w settings.py wymusić wartość tej zmiennej, np:
authors = Author.objects.filter(id__in=author_ids.split(','))
Powyższy przykład nie będzie działać jeżeli author_ids jest pusty.
Django wyrzuci wyjątek jeżeli do pola DecimalField przypisana zostanie wartość typu Float.
Zmianie uległ układ ogólnych widoków resetowania hasła. Obecnie do użytkownika wysyłany jest email z linkiem do formularza zmiany hasła. Token staje się nieaktywny po 3 dniach od wygenerowania lub po użyciu w tym czasie.
- Sterownik keszu "simple" został usunięty. Zaleca się używanie "locmem"
- Klasa `ObjectPaginator` została usunięta. Zaleca się stosowanie klas Paginator/Page
- Argument `edit_inline_type` dla `ForeignKey` został usunięty.
- Klasy `QOperator`, `QNot`, `QAnd` i `QOr` zostały usunięte. Należy używać klasy Q.
- Argument `maxlength` usunięty (zastąpiony przez `max_length`)
- `request[key]` -> `request.REQUEST[key]`
- `key in request` -> `key in request.REQUEST`
- `request.has_key(key)` -> `request.REQUEST.has_key(key)`
Zaszły liczne zmiany w podsystemie sygnałów i slotów, które znacząco poprawiły ich wydajność. Obecną budowę tego komponentu znajdziemy w dokumentacji.
`save_add` i `save_change` zostały usunięte, a `response_add` i
`response_change` zostały dodane.
- Usunięto możliwość wyświetlania plików jako napisów. Należy używać django.core.files.base.ContentFile
- Usunięto dostęp do załadowanych plików przez słowniki. Należy używać django.core.files.uploadedfile.SimpleUploadedFile
- Właściwości `filename`, `file_name`, `file_size`, i `chuck` zostały usunięty z `UploadedFile. Należy stosować `name`, `size` i `chunks`
- Metody `get_FIELD_filename`, `get_FIELD_url`, `get_FIELD_size` i `save_FIELD_file` dla modeli z `FileField` zostały usunięte.
- Metody `get_FIELD_width` i `get_FIELD_height` dla modeli z `ImageField` zostały usunięte.
- Funkcje `connect`, `disconnect`, `send` i `sendExact` z "dispatchera" zostały usunięte.
- Funkcje form_for_model` i `form_for_instance` zostały usunięte na żecz `ModelForm`.
- Usunięto `django.utils.images` na żecz `django.core.files.images`
- Argument `follow` w ogólnych widokach `create_object` i `update_object` został usunięty. Należy stosować `form_class` z newforms.
Zmianie uległa wewnętrzna konstrukcja sterowników do baz danych. Zmiana ta nie wpływa na działanie standardowych metod ORMa.
Własne sterowniki (backend) sesji muszą zawierać parametr "must_create" w metodach "save()". Domyślnie jego wartość ustawiona jest na False. W przypadku True nowy obiekt sesji musi zostać stworzony lub wyrzucony zostanie wyjątek.
Zmianie uległy nazw pól na lokalnych danych:
- PLPESELField
- PLNIPField
- PLREGONField
- PLProvinceSelect
- PLCountiesSelect
Nieudokumentowany stary system komentarzy został zastąpiony zupełnie nową aplikacją.
Nie można już uzyskać dostępu do pól ModelForm jako atrybuty. Można natomiast poprzez słownik.
- Dodane: 06.09.2008 przez riklaunim