Django 1.0 rompe la compatibilidad con 0.96 en algunas áreas.
Esta guía le ayudará a portar proyectos y aplicaciones de 0.96 a 1.0. La primera parte de este documento incluye los cambios comunes necesarios para ejecutarse con 1.0. Si después de pasar por la primera parte su código todavía se rompe, consulte la sección Cambios menos comunes para obtener una lista de un montón de problemas de compatibilidad menos comunes.
Ver también
Las notas de lanzamiento 1.0. Ese documento explica las nuevas características en 1.0 con más profundidad; la guía de portación se preocupa más por ayudarle a actualizar rápidamente su código.
Esta sección describe los cambios entre 0.96 y 1.0 que la mayoría de los usuarios necesitarán realizar.
Cambia las cadenas literales de caracteres (“foo”) en cadenas literales de Unicode (u’foo”). Django utiliza ahora cadenas Unicode en todas partes. En la mayoría de los lugares, las cadenas crudas seguirán funcionando, pero actualizar para utilizar cadenas literales de Unicode evitará algunos problemas obscuros.
Ver Datos Unicode para detalles completos.
Cambios comunes a tu archivo de modelos:
maxlength a max_length¶Renombra tu argumento maxlength a max_length (se cambió para ser consistente con los campos de formulario).
Sustituye la función de tu modelo __str__ por un método __unicode__, y asegúrate de que en ese método utilices Unicode (u’foo”).
Quitar el argumento prepopulated_from de los campos del modelo. Ya no es válido y se ha movido a la clase ModelAdmin en admin.py. Consulta la administración para obtener más detalles sobre los cambios realizados en la administración.
core¶Quita el argumento core de tus campos del modelo. Ya no es necesario, ya que la funcionalidad equivalente (parte de edición inline) se maneja de manera diferente por la interfaz de administración ahora. No tienes que preocuparte por la edición en línea hasta llegar a la administración sección, más abajo. Por ahora, quita todas las referencias a core.
class Admin: con admin.py¶Quita todas tus declaraciones de clase Admin internas de tus modelos. No romperán nada si las dejas, pero tampoco harán nada. Para registrar aplicaciones con la administración moverás esas declaraciones a un archivo admin.py; consulta la administración más abajo para obtener más detalles.
Ver también
Un contribuyente de djangosnippets__ ha escrito un script que escaneará tus archivos models.py y generará un archivo admin.py correspondiente.
A continuación, se muestra un ejemplo del archivo models.py con todas las modificaciones necesarias:
Modelo antiguo (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)
Nuevo (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)
Nuevo (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)
Uno de los cambios más grandes en 1.0 es el nuevo panel de administración. La interfaz administrativa de Django (django.contrib.admin) ha sido completamente reescrita; las definiciones de administrador ahora están completamente desacopladas de las definiciones de modelo, el marco se ha rediseñado para utilizar la biblioteca de manejo de formularios de Django y se ha diseñado con extensibilidad y personalización en mente.
Prácticamente, esto significa que necesitarás reescribir todas tus declaraciones de class Admin. Ya has visto en models cómo reemplazar tu class Admin con una llamada a admin.site.register() en un archivo admin.py. A continuación, se presentan algunos detalles adicionales sobre cómo reescribir esa declaración de Admin en la nueva sintaxis.
Las nuevas opciones de edit_inline han sido movidas a admin.py. Aquí tienes un ejemplo:
Old (0,96):
class Parent(models.Model): ...
class Child(models.Model):
parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)
Nueva (1.0):
class ChildInline(admin.StackedInline):
model = Child
extra = 3
class ParentAdmin(admin.ModelAdmin):
model = Parent
inlines = [ChildInline]
admin.site.register(Parent, ParentAdmin)
Ver Objetos de InlineModelAdmin para más detalles.
fields, o utiliza fieldsets¶La documentación traducida es la siguiente:
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"}),
)
Nueva (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"}),
)
Ver también
Puedes encontrar más información detallada sobre los cambios y las razones detrás de ellos en la página wiki `NewformsAdminBranch`__.
La nueva administración viene con una tonelada de nuevas características; puedes leer sobre ellas en la documentación de administración.
urls.py¶Si estás utilizando el sitio de administración, necesitarás actualizar tu archivo raíz urls.py.
Antiguo (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 ...
)
Nueva (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 ...
)
Sustituye django.newforms por django.forms – Django 1.0 renombró el módulo newforms (introducido en 0.96) a simplemente forms. El módulo oldforms también fue eliminado.
Si ya estás utilizando la biblioteca newforms, y utilizaste nuestra recomendada sintaxis de declaración de importación, todo lo que tienes que hacer es cambiar tus declaraciones de importación.
Anterior:
from django import newforms as forms
Nueva:
from django import forms
Si estás utilizando el sistema de formularios antiguo (anteriormente conocido como django.forms y django.oldforms), tendrás que reescribir tus formularios. Un buen lugar para empezar es la documentación sobre formularios
Sustituye el uso de archivos subidos – es decir, entradas en request.FILES – como simples diccionarios con el nuevo UploadedFile. La antigua sintaxis del diccionario ya no funciona.
Por lo tanto, en una vista como:
def my_view(request):
f = request.FILES["file_field_name"]
...
…tendrías que hacer los siguientes cambios:
Anterior (0.96) |
Nuevo (1.0) |
|---|---|
f[“content”] |
f.read() |
f[“filename”] |
f.name |
f[“content-type”] |
f.content_type |
La implementación interna de :class:`django.db.models.FileField ha cambiado. Un resultado visible de esto es que la forma en que accedes a las atributos especiales (URL, nombre del archivo, tamaño de imagen, etc.) de estos campos de modelo ha cambiado. Tendrás que realizar los siguientes cambios, asumiendo que el campo de tu modelo llamado myfile es de tipo :class:`~django.db.models.FileField`.
Anterior (0.96) |
Nuevo (1.0) |
|---|---|
myfile.get_content_filename() |
|
|
|
|
|
|
|
|
|
|
|
Ten en cuenta que las atributos width y height solo tienen sentido para los campos de tipo ImageField. Para obtener más detalles, consulte la documentación del API de modelos <ref/models/fields>.
Paginator en lugar de ObjectPaginator¶La clase ObjectPaginator en 0.96 ha sido eliminada y reemplazada con una versión mejorada, django.core.paginator.Paginator.
Por defecto, el sistema de plantillas ahora escapa automáticamente el HTML del resultado de cada variable. Para obtener más información, consulte Escape HTML automático.
Para deshabilitar la autoescapación para una variable individual, utiliza el filtro safe:
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
Para deshabilitar la autoescapación para toda la plantilla, envuelve la plantilla (o solo una sección particular de ella) en el etiqueta autoescape:
{% autoescape off %}
... unescaped template content here ...
{% endautoescape %}
Los siguientes cambios son más pequeños y localizados. Solo deberían afectar a usuarios avanzados, pero probablemente sea útil leer la lista y comprobar su código para estos aspectos.
Añade **kwargs a cualquier manejador de señal registrado.
Conecta, desconecta y envía señales a través de métodos en el objeto Signal en lugar de a través de métodos del módulo en django.dispatch.dispatcher.
Elimina cualquier uso de las opciones del remitente Anonymous y Any; ya no existen. Puedes seguir recibiendo señales enviadas por cualquier remitente utilizando sender=None
Declara cualquier señal personalizada que hayas declarado como instancias de django.dispatch.Signal en lugar de objetos anónimos.
Aquí tienes un resumen rápido de los cambios en el código que debes realizar:
Anterior (0.96) |
Nuevo (1.0) |
|---|---|
def callback(sender) |
def callback(sender, **kwargs) |
|
|
|
|
|
|
|
|
django.contrib.localflavor.usa ha sido renombrado a django.contrib.localflavor.us. Esta modificación se realizó para coincidir con el esquema de nombres de otros sabores locales. Para migrar su código, todo lo que necesitan hacer es cambiar las importaciones.
SessionBase.get_new_session_key() ha sido renombrado a _get_new_session_key(). get_new_session_object() ya no existe.
save()¶Anteriormente, cargar una fila ejecutaba automáticamente el método save() del modelo. Esto ya no es el caso, por lo que cualquier campo (por ejemplo: timestamps) que se pobló automáticamente mediante un save() ahora requiere valores explícitos en cualquier archivo de pruebas.
La antigua EnvironmentError se ha dividido en una ImportError cuando Django no puede encontrar el módulo de configuración y un RuntimeError cuando intentas reconfigurar la configuración después de haberla utilizado ya.
LOGIN_URL se ha movido¶La constante LOGIN_URL se ha movido del módulo django.contrib.auth al módulo de configuración. En lugar de utilizar from django.contrib.auth import LOGIN_URL, refiérete a la constante settings.LOGIN_URL.
APPEND_SLASH se ha actualizado¶En 0.96, si una URL no terminaba en un slash o tenía un período en el componente final de su ruta y APPEND_SLASH era Verdadero, Django redirigía a la misma URL, pero con un slash agregado al final. Ahora, Django verifica si el patrón sin el trailing slash se corresponde con algo en tus patrones de URL. Si es así, no tiene lugar ninguna redirección, ya que se asume que deseas capturar deliberadamente ese patrón.
Para la mayoría de las personas, esto no requerirá cambios. Algunas personas, sin embargo, tienen patrones de URL que parecen esto:
r"/some_prefix/(.*)$"
Anteriormente, esos patrones habrían sido redirigidos para tener un trailing slash. Si siempre deseas un slash en tales URLs, reescribe el patrón como:
r"/some_prefix/(.*/)$"
get()¶Los administradores ahora devuelven una excepción MultipleObjectsReturned en lugar de AssertionError:
Old (0,96):
try:
Model.objects.get(...)
except AssertionError:
handle_the_error()
Nueva (1.0):
try:
Model.objects.get(...)
except Model.MultipleObjectsReturned:
handle_the_error()
LazyDate ha sido despedido¶La clase auxiliar LazyDate ya no existe.
Los valores predeterminados de los campos y las argumentos de consulta pueden ser objetos callable, por lo que instancias de LazyDate se pueden reemplazar con una referencia a datetime.datetime.now:
Old (0,96):
class Article(models.Model):
title = models.CharField(maxlength=100)
published = models.DateField(default=LazyDate())
Nueva (1.0):
import datetime
class Article(models.Model):
title = models.CharField(max_length=100)
published = models.DateField(default=datetime.datetime.now)
DecimalField es nuevo, y FloatField ahora es un float propiamente dicho¶Old (0,96):
class MyModel(models.Model):
field_name = models.FloatField(max_digits=10, decimal_places=3)
...
Nueva (1.0):
class MyModel(models.Model):
field_name = models.DecimalField(max_digits=10, decimal_places=3)
...
Si olvidas hacer este cambio, verás errores sobre FloatField que no toman el atributo max_digits en __init__, porque el nuevo FloatField no acepta argumentos relacionados con la precisión.
Si estás utilizando MySQL o PostgreSQL, no se necesitan cambios adicionales. Los tipos de columna de base de datos para DecimalField son los mismos que para el antiguo FloatField.
Si estás utilizando SQLite, necesitarás forzar a la base de datos a ver las columnas correspondientes como tipos decimales en lugar de flotantes. Para hacer esto, deberás recargar tus datos. Hazlo después de haber realizado el cambio para utilizar DecimalField en tu código y haber actualizado el código de Django.
Advertencia
Vuelve a hacer una copia de seguridad de tu base de datos primero!
Para SQLite, esto significa hacer una copia del único archivo que almacena la base de datos (el nombre de ese archivo es el DATABASE_NAME en tu archivo settings.py).
Para actualizar cada aplicación para utilizar un campo DecimalField, puedes realizar lo siguiente, reemplazando <app> en el código a continuación con el nombre de cada app:
$ ./manage.py dumpdata --format=xml <app> > data-dump.xml
$ ./manage.py reset <app>
$ ./manage.py loaddata data-dump.xml
Notas:
Es importante que recuerdes usar formato XML en la primera etapa de este proceso. Estamos explotando una característica de las copias de datos XML que hace posible portar flotantes a decimales con SQLite.
En la segunda etapa, se te pedirá confirmar que estás preparado para perder los datos de la aplicación(s) en cuestión. Diga sí; restauraremos estos datos en la tercera etapa.
El campo DecimalField no se utiliza en ninguna de las aplicaciones incluidas con Django antes de que se realice este cambio, por lo que no necesitas preocuparte por realizar este procedimiento para ninguno de los modelos estándar de Django.
Si algo sale mal en el proceso anterior, simplemente copia tu archivo de base de datos respaldado sobre el archivo original y vuelve a empezar.
django.views.i18n.set_language() ahora requiere una solicitud POST¶Anteriormente, se utilizaba una solicitud GET. El comportamiento antiguo significaba que el estado (la configuración regional utilizada para mostrar el sitio) podía ser cambiado mediante una solicitud GET, lo cual va en contra de las recomendaciones de la especificación HTTP. El código que llama a esta vista debe asegurarse de que ahora se hace una solicitud POST en lugar de una GET. Esto significa que ya no puedes utilizar un enlace para acceder a la vista, sino que debes usar una solicitud de formulario de alguna clase (por ejemplo, un botón).
_() ya no está en builtins¶_() (el objeto callable cuyo nombre es un guión bajo) ya no se ha monkeypatcheado a builtins – es decir, ya no está disponible mágicamente en cada módulo.
Si estabas confiando en que _() siempre estaría presente, ahora debes importar explícitamente ugettext o ugettext_lazy, si corresponde, y asignarlo a _ tú mismo:
from django.utils.translation import ugettext as _
HttpRequest¶Los objetos HttpRequest ya no admiten directamente el acceso al diccionario; anteriormente, tanto los datos GET como POST estaban disponibles directamente en el objeto HttpRequest (por ejemplo, podías comprobar la presencia de una pieza de formulario utilizando if 'some_form_key' in request o leyendo request['some_form_key']. Esto ya no está soportado; si necesitas acceso a los datos combinados GET y POST, utiliza request.REQUEST en su lugar.
Sin embargo, se sugiere fuertemente que siempre busques explícitamente en el diccionario adecuado para el tipo de solicitud que esperas recibir (request.GET o request.POST); confiar en el diccionario combinado request.REQUEST puede ocultar la procedencia de los datos entrantes.
HTTPResponse¶django.http.HttpResponse.headers se ha renombrado a _headers y HttpResponse ahora admite comprobaciones de contención directamente. Por lo tanto, utiliza if header in response: en lugar de if header in response.headers:.
Las clases de relación genérica – GenericForeignKey y GenericRelation – se han movido al módulo django.contrib.contenttypes.
django.test.Client.login() ha cambiado¶Old (0,96):
from django.test import Client
c = Client()
c.login("/path/to/login", "myuser", "mypassword")
Nueva (1.0):
# ... same as above, but then:
c.login(username="myuser", password="mypassword")
El módulo django.core.management se ha refacturado en gran medida.
Las llamadas a servicios de gestión en tu código necesitan ahora utilizar call_command. Por ejemplo, si tienes algún código de prueba que llama a flush y load_data:
from django.core import management
management.flush(verbosity=0, interactive=False)
management.load_data(["test_data"], verbosity=0)
…debes cambiar este código para que lea:
from django.core import management
management.call_command("flush", verbosity=0, interactive=False)
management.call_command("loaddata", "test_data", verbosity=0)
Ahora django-admin.py y manage.py requieren que los subcomandos precedan a las opciones.
$ django-admin.py --settings=foo.bar runserver
No funciona ya y debe ser cambiado a:
$ django-admin.py runserver --settings=foo.bar
django.newforms.forms.SortedDictFromList se eliminó. django.utils.datastructures.SortedDict ahora puede instanciarse con una secuencia de tuplas.
Actualiza tu código:
Los textos traducidos son:
Porque django.utils.datastructures.SortedDict.copy no devuelve una copia profunda como lo hacía SortedDictFromList.copy(), necesitarás actualizar tu código si estabas confiando en una copia profunda. Haz esto utilizando directamente copy.deepcopy.
Casi todos las funciones a nivel de backend de la base de datos han sido renombradas y/o reubicadas. Ninguna de estas estaba documentada, pero necesitarás cambiar tu código si estabas utilizando alguna de estas funciones, todas las cuales están en django.db:
Anterior (0.96) |
Nuevo (1.0) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
may 31, 2026
Comentarios¶
Si estabas utilizando la aplicación
django.contrib.commentsde Django 0.96, necesitarás actualizar a la nueva aplicación de comentarios introducida en 1.0. Consulta el documento de actualización para obtener más detalles.