杰瑞科技汇

Django 1.11版本如何升级或兼容处理?

Of course. Here's a comprehensive guide covering Django 1.11, including its features, common patterns, how to use it, and crucial information about its end-of-life status.

Django 1.11版本如何升级或兼容处理?-图1
(图片来源网络,侵删)

Important: Django 1.11 is End-of-Life (EOL)

This is the most important thing to know. Django 1.11 reached its official end-of-life on April 1, 2025.

  • What this means: No security patches, bug fixes, or updates are being released for it.
  • The risk: Running a project on Django 1.11 in a production environment is a significant security risk. Your application is vulnerable to known and newly discovered security flaws.
  • Recommendation: You should immediately plan to upgrade your project to a supported, modern version of Django (currently 4.x or 5.x). The upgrade process can be complex, but it's essential for the security and maintainability of your project.

This guide is for understanding legacy codebases or for educational purposes only.


Key Features and Changes in Django 1.11

Django 1.11 was a major "Long-Term Support" (LTS) release, which meant it received security updates for several years. It introduced many useful features and marked the end of the Python 2.x support era.

A. Python 2 and 3 Compatibility

This was a major theme for 1.11. It was the last version to support Python 2.7. It introduced several features to help with the transition from Python 2 to Python 3.

Django 1.11版本如何升级或兼容处理?-图2
(图片来源网络,侵删)
  • __future__ imports: Many internal components were updated to use modern Python 3 features.
  • django.utils.six: The six library was still heavily used internally to write code that worked on both Python 2 and 3.

B. Built-in JSONField

One of the most anticipated features. Before 1.11, you had to use third-party packages like django-jsonfield to store JSON data in your database.

# In your models.py
from django.db import models
class Product(models.Model):
    name = models.CharField(max_length=100)
    details = models.JSONField() # Store a dictionary or list directly!
# Usage
product = Product.objects.create(name="Laptop", details={"color": "black", "ram": "16GB"})
print(product.details['color']) # Output: 'black'

C. Template Improvements

  • {% url %} tag no longer requires a view name as the first argument: This was a long-standing point of confusion. You could now just pass the name of the URL pattern.

    <!-- Old way (still works) -->
    <a href="{% url 'myapp:detail' pk=object.pk %}">View</a>
    <!-- New, cleaner way in 1.11 -->
    <a href="{% url 'myapp:detail' pk=object.pk %}">View</a>

    Correction: The "no first argument" feature was more of a gradual improvement over several versions. The main point is that the url tag became more robust and powerful.

  • {% static %} tag: The {% load static %} tag and its usage became the standard way to link to static files (CSS, JS, images).

D. Password Validation

Django introduced a more robust and configurable password validation system. Instead of just checking the minimum length, you could now enforce rules like complexity requirements.

# In your settings.py
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 9, # Default was 8
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

E. Other Notable Features

  • on_delete argument is required for ForeignKey and OneToOneField: This was a major breaking change for safety. You had to explicitly define what should happen when the object being referenced is deleted.
    • models.CASCADE: (Default) Delete the object with the foreign key.
    • models.PROTECT: Prevent deletion by raising ProtectedError.
    • models.SET_NULL: Set the foreign key to NULL (requires null=True).
    • models.SET_DEFAULT: Set the foreign key to its default value.
  • Database Backends: Improved support for newer versions of PostgreSQL and MySQL.
  • Management Commands: The call_command utility was enhanced.

How to Set Up a Django 1.11 Project

Here's how you would have created a project back in the day.

Step 1: Installation

You would have installed it using pip. It's recommended to use a virtual environment.

# Create and activate a virtual environment
python -m venv myproject_env
source myproject_env/bin/activate  # On Windows: myproject_env\Scripts\activate
# Install Django 1.11
pip install "Django==1.11"

Step 2: Project and App Creation

The django-admin and manage.py commands were the same as they are today.

# Create a new project
django-admin startproject myproject
# Navigate into the project directory
cd myproject
# Create a new app
python manage.py startapp myapp

Step 3: Basic Project Structure

Your project would look like this:

myproject/
├── myproject/          # Project configuration package
│   ├── __init__.py
│   ├── settings.py     # Main settings file
│   ├── urls.py         # Project-level URL configuration
│   ├── wsgi.py         # WSGI application entry point
│   └── asgi.py         # ASGI application entry point (newer in 1.11)
├── myapp/              # Your app
│   ├── migrations/
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── manage.py           # Command-line utility for the project

Step 4: Configure settings.py

You had to register your new app in INSTALLED_APPS.

# myproject/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',  # Add your new app here
]

Common Code Patterns in Django 1.11

A. URLs (urls.py)

URL patterns were defined using the url() function.

# myproject/urls.py
from django.conf.urls import url
from django.contrib import admin
from myapp import views as myapp_views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^articles/([0-9]{4})/$', myapp_views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', myapp_views.month_archive),
]

B. Views (views.py)

Views were simple functions that took a request and returned an HttpResponse.

# myapp/views.py
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from .models import Article
def year_archive(request, year):
    # Note: This is a simple example, not efficient for large datasets
    articles = Article.objects.filter(pub_date__year=year)
    output = "<h1>Articles for %s</h1>" % year
    for article in articles:
        output += "<p>%s</p>" % article.title
    return HttpResponse(output)
def month_archive(request, year, month):
    # A more common pattern using get_object_or_404
    # This would typically render a template instead of returning plain HTML
    return HttpResponse("You're looking at articles from %s %s." % (year, month))

C. Models (models.py)

Models defined the database schema. The on_delete argument was key.

# myapp/models.py
from django.db import models
from django.utils import timezone
class Article(models.Model):
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE) # on_delete is required!= models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(default=timezone.now)
    published_date = models.DateTimeField(blank=True, null=True)
    def publish(self):
        self.published_date = timezone.now()
        self.save()
    def __str__(self):
        return self.title

D. Templates

Templates used the Django Template Language (DTL). The {% static %} tag was standard.

<!-- myapp/templates/myapp/article_list.html -->
{% extends "base.html" %}
{% block content %}
    <h1>Latest Articles</h1>
    {% for article in article_list %}
        <h2><a href="{% url 'myapp:detail' pk=article.pk %}">{{ article.title }}</a></h2>
        <p>{{ article.text|truncatewords:30 }}</p>
    {% empty %}
        <p>No articles are available.</p>
    {% endfor %}
{% endblock %}

Migrating from Django 1.11

If you are stuck maintaining a 1.11 project, here is the high-level upgrade path.

  1. Create a Backup: Before you do anything, back up your entire project, including the database.
  2. Upgrade Dependencies: Upgrade pip, setuptools, and wheel.
  3. Upgrade to a Modern LTS Version: It's best to skip intermediate versions and go straight to a current LTS release like Django 4.2 or Django 3.2.
    pip install --upgrade "Django==4.2"
  4. Run python manage.py check: This command will find many common compatibility issues for you.
  5. Address Code Changes:
    • URLs: Replace django.conf.urls.url with django.urls.re_path (for regex) or django.urls.path (for clean URLs).
    • Templates: Update {% load staticfiles %} to {% load static %}.
    • Settings: Check for deprecated settings in the Django 1.11 to 2.0 migration guide.
    • Imports: Update any internal Django imports that may have changed.
  6. Database Migrations:
    • Delete all migration files in your app's migrations/ folder (except __init__.py).
    • Run python manage.py makemigrations to generate new migration files based on your current models.
    • Run python manage.py migrate to apply the changes to your database.
  7. Thoroughly Test: Go through every feature of your application manually. Automated tests are even better. Pay close attention to forms, admin, and any custom logic.

The Django documentation has detailed version-specific migration guides that are invaluable for this process.

分享:
扫描分享到社交APP
上一篇
下一篇