Porta dina appar från Django 0.96 till 1.0

Django 1.0 bryter kompatibiliteten med 0.96 i vissa områden.

Den här guiden hjälper dig att porta 0.96-projekt och appar till 1.0. Den första delen av detta dokument innehåller de vanliga ändringar som behövs för att köra med 1.0. Om din kod fortfarande inte fungerar efter att du har gått igenom den första delen kan du läsa avsnittet Mindre vanliga ändringar för en lista över ett antal mindre vanliga kompatibilitetsproblem.

Se även

Den 1.0 release notes. Det dokumentet förklarar de nya funktionerna i 1.0 mer ingående; portningsguiden är mer inriktad på att hjälpa dig att snabbt uppdatera din kod.

Vanliga förändringar

I detta avsnitt beskrivs de ändringar mellan 0.96 och 1.0 som de flesta användare kommer att behöva göra.

Använd Unicode

Ändra stränglitteraler ('foo') till Unicode-litteraler (u'foo'). Django använder nu Unicode-strängar genomgående. På de flesta ställen kommer råa strängar att fortsätta att fungera, men uppdatering till att använda Unicode-litteraler kommer att förhindra vissa obskyra problem.

Se Unicode-data för fullständig information.

Modeller

Vanliga ändringar i din models-fil:

Byt namn på maxlength till max_length

Byt namn på argumentet maxlength till max_length (detta ändrades för att vara konsekvent med formulärfält):

Ersätt __str__ med __unicode__

Ersätt din modells funktion __str__ med en metod __unicode__ och se till att du använder Unicode (u'foo') i den metoden.

Ta bort prepopulated_from

Ta bort prepopulated_from-argumentet på modellfält. Det är inte längre giltigt och har flyttats till klassen ModelAdmin i admin.py. Se admin nedan för mer information om ändringar i admin.

Ta bort kärna

Ta bort core-argumentet från dina modellfält. Det är inte längre nödvändigt, eftersom motsvarande funktionalitet (en del av inline editing) hanteras annorlunda av admin-gränssnittet nu. Du behöver inte oroa dig för inline-redigering förrän du kommer till avsnittet Admin nedan. För tillfället, ta bort alla referenser till core.

Ersätt class Admin: med admin.py

Ta bort alla dina inre class Admin-deklarationer från dina modeller. De kommer inte att förstöra något om du låter dem vara kvar, men de kommer inte heller att göra något. För att registrera appar med administratören kommer du att flytta dessa deklarationer till en admin.py-fil; se the admin nedan för mer information.

Se även

En bidragsgivare till djangosnippets har skrivit ett skript som söker igenom din models.py och genererar en motsvarande admin.py.

Exempel

Nedan följer ett exempel på filen models.py med alla de ändringar du behöver göra:

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

Ny (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 "%s %s" % (self.first_name, self.last_name)

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

Administratören

En av de största förändringarna i 1.0 är den nya administratören. Djangos administrativa gränssnitt (django.contrib.admin) har helt omarbetats; admin-definitioner är nu helt frikopplade från modelldefinitioner, ramverket har skrivits om för att använda Djangos nya formulärhanteringsbibliotek och omdesignats med tanke på utdragbarhet och anpassning.

I praktiken innebär det att du måste skriva om alla dina class Admin-deklarationer. Du har redan sett i models ovan hur du kan ersätta din class Admin med ett admin.site.register()-anrop i en admin.py-fil. Nedan följer lite mer information om hur man skriver om Admin deklarationen till den nya syntaxen.

Använd ny inline-syntax

De nya edit_inline-alternativen har alla flyttats till admin.py. Här är ett exempel:

Gammal (0,96):

class Parent(models.Model): ...


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

Ny (1.0):

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


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


admin.site.register(Parent, ParentAdmin)

Se objekt av typen ``InlineModelAdmin för mer information.

Förenkla fields, eller använd fieldsets

Den gamla syntaxen fields var ganska förvirrande och har förenklats. Den gamla syntaxen fungerar fortfarande, men du måste använda fieldsets istället.

Gammal (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"}),
        )

Ny (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"}),
    )

Se även

  • Mer detaljerad information om ändringarna och orsakerna bakom dem finns på wikisidan NewformsAdminBranch

  • Den nya admin kommer med massor av nya funktioner; du kan läsa om dem i admin dokumentation.

URL:er

Uppdatera din root urls.py

Om du använder administratörssidan måste du uppdatera din root urls.py.

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

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

Vyer

Använd django.forms istället för newforms

Ersätt django.newforms med django.forms – Django 1.0 bytte namn på modulen newforms (introducerad i 0.96) till gamla vanliga forms. Modulen oldforms togs också bort.

Om du redan använder biblioteket newforms och du använde vår rekommenderade syntax för import-satser behöver du bara ändra dina importsatser.

Gammal:

from django import newforms as forms

Ny:

from django import forms

Om du använder det gamla formulärsystemet (tidigare känt som django.forms och django.oldforms) måste du skriva om dina formulär. Ett bra ställe att börja på är formulärdokumentation

Hantera uppladdade filer med hjälp av det nya API:et

Ersätt användningen av uppladdade filer - det vill säga poster i request.FILES - som enkla ordböcker med den nya UploadedFile. Den gamla syntaxen för ordböcker fungerar inte längre.

Alltså, i en vy som:

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

…måste du göra följande ändringar:

Gammal (0,96)

Ny (1.0)

f['innehåll']`

f.read()`

f['filnamn']

f.namn

f['content-type']`

f.content_type

Arbeta med filfält med hjälp av det nya API:et

Den interna implementeringen av django.db.models.FileField har ändrats. Ett synligt resultat av detta är att sättet du kommer åt specialattribut (URL, filnamn, bildstorlek etc.) för dessa modellfält har ändrats. Du kommer att behöva göra följande ändringar, förutsatt att din modells FileField heter myfile:

Gammal (0,96)

Ny (1.0)

myfile.get_content_filename()

minfil.innehåll.sökväg

myfile.get_content_url()

minfil.innehåll.url

myfile.get_content_size()

minfil.innehåll.storlek

myfile.save_content_file()

myfile.content.save()

myfile.get_content_width()

myfile.content.width

myfile.get_content_height()

myfile.content.height

Observera att attributen width och height endast är meningsfulla för ImageField-fält. Mer information finns i dokumentationen model API.

Använd Paginator istället för ObjectPaginator

ObjectPaginator i 0.96 har tagits bort och ersatts med en förbättrad version, django.core.paginator.Paginator.

Mallar

Lär dig att älska autoescaping

Som standard HTML-eskapsätter mallsystemet nu automatiskt utdata från varje variabel. För mer information, se Automatisk HTML-escaping.

Om du vill inaktivera automatisk eskapning för en enskild variabel använder du filtret safe:

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

Om du vill inaktivera auto-escaping för en hel mall, linda in mallen (eller bara en viss del av mallen) i taggen autoescape:

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

Mindre vanliga förändringar

Följande ändringar är mindre, mer lokala ändringar. De bör endast påverka mer avancerade användare, men det är förmodligen värt att läsa igenom listan och kontrollera din kod för dessa saker.

Signaler

  • Lägg till **kwargs till alla registrerade signalhanterare.

  • Anslut, koppla från och skicka signaler via metoder på objektet Signal istället för via modulmetoder i django.dispatch.dispatcher.

  • Ta bort all användning av avsändaralternativen Anonymous och Any; de finns inte längre. Du kan fortfarande ta emot signaler som skickas av vilken avsändare som helst genom att använda sender=None

  • Gör alla anpassade signaler som du har deklarerat till instanser av django.dispatch.Signal istället för anonyma objekt.

Här är en snabb sammanfattning av de kodändringar du behöver göra:

Gammal (0,96)

Ny (1.0)

def callback(avsändare)

def callback(avsändare, **kwargs)

sig = objekt()

sig = django.dispatch.Signal()

dispatcher.connect(callback, sig)`

sig.connect(callback)

dispatcher.send(sig, avsändare)

sig.send(avsändare)

dispatcher.connect(callback, sig, avsändare=Any)

sig.connect(callback, avsändare=None)

Kommentarer

Om du använde Django 0.96:s app django.contrib.comments måste du uppgradera till den nya kommentarsappen som introducerades i 1.0. Se uppgraderingsguiden för mer information.

Malltaggar

utrymmeslös tagg

Malltaggen spaceless tar nu bort alla mellanslag mellan HTML-taggar, istället för att bevara ett enda mellanslag.

Lokala smaker

Lokal smak från USA

django.contrib.localflavor.usa har bytt namn till django.contrib.localflavor.us. Denna förändring gjordes för att matcha namngivningsschemat för andra lokala smaker. För att migrera din kod är allt du behöver göra att ändra importen.

Sessioner

Få en ny sessionsnyckel

SessionBase.get_new_session_key() har bytt namn till _get_new_session_key(). get_new_session_object() finns inte längre.

Fixturer

Laddning av en rad kräver inte längre save()

Tidigare körde laddning av en rad automatiskt modellens save()-metod. Detta är inte längre fallet, så alla fält (till exempel: tidsstämplar) som automatiskt fylldes i av en save() behöver nu uttryckliga värden i alla fixturer.

Inställningar

Bättre undantag

Det gamla EnvironmentError har delats upp i ett ImportError när Django misslyckas med att hitta inställningsmodulen och ett RuntimeError när du försöker konfigurera om inställningar efter att du redan har använt dem.

LOGIN_URL har flyttats

Konstanten LOGIN_URL flyttades från django.contrib.auth till modulen settings. Istället för att använda from django.contrib.auth import LOGIN_URL hänvisa till settings.LOGIN_URL.

APPEND_SLASH-beteendet har uppdaterats

I 0.96, om en URL inte slutade med ett snedstreck eller hade en punkt i den sista komponenten i sökvägen, och APPEND_SLASH var True, skulle Django omdirigera till samma URL, men med ett snedstreck i slutet. Nu kontrollerar Django för att se om mönstret utan det efterföljande snedstrecket skulle matchas av något i dina URL-mönster. Om så är fallet sker ingen omdirigering, eftersom det antas att du avsiktligt ville fånga det mönstret.

För de flesta människor kommer detta inte att kräva några ändringar. Vissa människor har dock URL-mönster som ser ut så här:

r"/some_prefix/(.*)$"

Tidigare skulle dessa mönster ha omdirigerats till att ha ett efterföljande snedstreck. Om du alltid vill ha ett snedstreck på sådana webbadresser skriver du om mönstret till:

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

Mindre modellförändringar

Olika undantag från get()

Hanterare returnerar nu ett MultipleObjectsReturned undantag istället för AssertionError:

Gammal (0,96):

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

Ny (1.0):

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

LazyDate har avfyrats

Hjälpklassen LazyDate finns inte längre.

Standardfältvärden och frågeargument kan båda vara anropsbara objekt, så instanser av LazyDate kan ersättas med en referens till datetime.datetime.now:

Gammal (0,96):

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

Ny (1.0):

import datetime


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

DecimalField är ny, och FloatField är nu en riktig float

Gammal (0,96):

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

Ny (1.0):

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

Om du glömmer att göra denna ändring kommer du att se fel om att FloatField inte tar ett max_digits-attribut i __init__, eftersom den nya FloatField inte tar några precisionsrelaterade argument.

Om du använder MySQL eller PostgreSQL behövs inga ytterligare ändringar. Databasens kolumntyper för DecimalField är desamma som för den gamla FloatField.

Om du använder SQLite måste du tvinga databasen att visa de aktuella kolumnerna som decimaltyper i stället för flyttal. För att göra detta måste du ladda om dina data. Gör detta efter att du har gjort ändringen till att använda DecimalField i din kod och uppdaterat Django-koden.

Varning

Säkerhetskopiera din databas först!

För SQLite innebär detta att du gör en kopia av den enda fil som lagrar databasen (namnet på den filen är DATABASE_NAME i filen settings.py).

För att uppgradera varje applikation till att använda en DecimalField kan du göra följande och ersätta <app> i koden nedan med varje apps namn:

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

Anteckningar:

  1. Det är viktigt att du kommer ihåg att använda XML-format i det första steget av den här processen. Vi utnyttjar en funktion i XML-datadumparna som gör det möjligt att porta floats till decimaler med SQLite.

  2. I det andra steget kommer du att bli ombedd att bekräfta att du är beredd att förlora data för applikationen/applikationerna i fråga. Säg ja, så återställer vi dessa data i det tredje steget.

  3. DecimalField används inte i någon av de appar som levererades med Django innan denna ändring gjordes, så du behöver inte oroa dig för att utföra denna procedur för någon av Djangos standardmodeller.

Om något går fel under processen ovan är det bara att kopiera den säkerhetskopierade databasfilen över originalfilen och börja om.

Internationalisering

django.views.i18n.set_language() kräver nu en POST-begäran

Tidigare användes en GET-begäran. Det gamla beteendet innebar att state (den locale som används för att visa webbplatsen) kunde ändras genom en GET-begäran, vilket strider mot HTTP-specifikationens rekommendationer. Kod som anropar denna vy måste se till att en POST-begäran nu görs, istället för en GET. Det innebär att du inte längre kan använda en länk för att komma åt vyn, utan du måste använda någon form av formulär (t.ex. en knapp).

_() finns inte längre i inbyggda program

_() (det anropsbara objektet vars namn är ett enda understreck) är inte längre monkeypatchat i builtins - det vill säga, det finns inte längre magiskt tillgängligt i varje modul.

Om du tidigare förlitade dig på att _() alltid skulle finnas, bör du nu uttryckligen importera ugettext eller ugettext_lazy, om det är lämpligt, och alias det till _ själv:

from django.utils.translation import ugettext as _

Objekt för HTTP-begäran/-svar

Dictionary-åtkomst till HttpRequest

objekten HttpRequest stöder inte längre direkt åtkomst i ordboksstil; tidigare var både GET och POST data direkt tillgängliga på objektet HttpRequest (t.ex. kunde du söka efter en bit formulärdata genom att använda if 'some_form_key' in request eller genom att läsa request['some_form_key']. Detta stöds inte längre; om du behöver tillgång till kombinerade GET och POST data, använd request.REQUEST istället.

Det rekommenderas dock starkt att du alltid uttryckligen letar i lämplig ordbok efter den typ av begäran du förväntar dig att få (request.GET eller request.POST); att förlita sig på den kombinerade ordboken request.REQUEST kan maskera ursprunget till inkommande data.

Tillgång till HTTPResponse-rubriker

django.http.HttpResponse.headers har bytt namn till _headers och HttpResponse stöder nu containment checking direkt. Så använd if header in response: istället för if header in response.headers:.

Generiska relationer

Generiska relationer har flyttats ut ur kärnan

De generiska relationsklasserna - GenericForeignKey och GenericRelation - har flyttats till modulen django.contrib.contenttypes.

Testar

django.test.Client.login() har ändrats

Gammal (0,96):

from django.test import Client

c = Client()
c.login("/path/to/login", "myuser", "mypassword")

Ny (1.0):

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

Ledningskommandon

Kör kommandon för hantering från din kod

django.core.management har genomgått en omfattande omarbetning.

Anrop till hanteringstjänster i din kod måste nu använda call_command. Om du till exempel har en testkod som anropar flush och load_data:

from django.core import management

management.flush(verbosity=0, interactive=False)
management.load_data(["test_data"], verbosity=0)

…måste du ändra den här koden så att den lyder:

from django.core import management

management.call_command("flush", verbosity=0, interactive=False)
management.call_command("loaddata", "test_data", verbosity=0)

Underkommandon måste nu föregå alternativ

django-admin.py och manage.py kräver nu att underkommandon föregår alternativen. Så här är det:

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

…fungerar inte längre och bör ändras till:

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

Syndikering

Feed.__init__ har ändrats

Metoden __init__() i syndikeringsramverkets klass Feed tar nu ett HttpRequest-objekt som sin andra parameter, istället för feedens URL. Detta gör att syndikeringsramverket kan fungera utan att kräva webbplatsramverket. Detta påverkar endast kod som subklassar Feed och åsidosätter metoden __init__(), och kod som anropar Feed.__init__() direkt.

Datastrukturer

SortedDictFromList är borta

django.newforms.forms.SortedDictFromList togs bort. django.utils.datastructures.SortedDict kan nu instansieras med en sekvens av tupler.

För att uppdatera din kod:

  1. Använd django.utils.datastructures.SortedDict där du tidigare använde django.newforms.forms.SortedDictFromList.

  2. Eftersom django.utils.datastructures.SortedDict.copy inte returnerar en deepcopy som SortedDictFromList.copy() gjorde, måste du uppdatera din kod om du förlitade dig på en deepcopy. Gör detta genom att använda copy.deepcopy direkt.

Funktioner för databasens backend

Databasens backend-funktioner har bytt namn

Nästan alla funktioner på databasens backend-nivå har bytt namn och/eller flyttats. Ingen av dessa har dokumenterats, men du måste ändra din kod om du använder någon av dessa funktioner, som alla finns i django.db:

Gammal (0,96)

Ny (1.0)

backend.get_autoinc_sql

anslutning.ops.autoinc_sql

backend.get_date_extract_sql

anslutning.ops.datum_extrahera_sql

backend.get_date_trunc_sql

anslutning.ops.datum_trunc_sql

backend.get_datetime_cast_sql

anslutning.ops.datetime_cast_sql

backend.get_deferrable_sql

anslutning.ops.deferrable_sql

backend.get_drop_foreignkey_sql

anslutning.ops.drop_foreignkey_sql

backend.get_fulltext_search_sql

anslutning.ops.fulltext_search_sql

backend.get_last_insert_id

anslutning.ops.sista_insättning_id

backend.get_limit_offset_sql

anslutning.ops.limit_offset_sql

backend.get_max_name_length

anslutning.ops.max_namn_längd

backend.get_pk_default_value

connection.ops.pk_default_value

backend.get_random_function_sql

anslutning.ops.random_function_sql

backend.get_sql_flush

anslutning.ops.sql_flush

backend.get_sql_sequence_reset

anslutning.ops.sequence_reset_sql

backend.get_start_transaction_sql

anslutning.ops.start_transaktion_sql

backend.get_tablespace_sql

anslutning.ops.tablespace_sql

backend.quote_name

anslutning.ops.quote_namn

backend.get_query_set_class

connection.ops.query_set_class

backend.get_field_cast_sql

anslutning.ops.fält_cast_sql

backend.get_drop_sequence

anslutning.ops.drop_sequence_sql

backend.OPERATOR_MAPPING

anslutning.operatörer

backend.tillåter_gruppering_per_ordinal

anslutning.funktioner.tillåter_gruppering_vid_ordinal

backend.allows_unique_and_pk

anslutning.funktioner.tillåter_unika_och_pk

backend.autoindexes_primära_nycklar

anslutning.funktioner.autoindex_primära_nycklar

backend.needs_datetime_string_cast

anslutning.funktioner.behöver_datatid_sträng_cast

backend.needs_upper_for_iops

anslutning.funktioner.behov_av_övre_del_för_iops

backend.stöd_begränsningar

anslutning.funktioner.stödjer_begränsningar

backend.stöder_bordsytor

anslutning.funktioner.stödjer_bordsytor

backend.uses_case_insensitive_names

connection.features.uses_case_insensitive_names

backend.uses_custom_queryset backend.uses_custom_queryset

anslutning.funktioner.använder_custom_queryset