Advanced Extensions
Advanced extensions in this codebase provide specialized functionality for handling dynamic relationships, advanced search capabilities, geographic data, and search engine optimization. These features are primarily implemented within django.contrib and are designed to integrate seamlessly with the core model system.
Content Types and Generic Relations
The contenttypes application allows models to relate to any other installed model in a generic way. This is particularly useful for building reusable components like tagging systems or comment engines that need to attach to multiple different types of content.
Core Components
ContentType: A model indjango.contrib.contenttypes.modelsthat represents other models in the system. Each row in theContentTypetable contains theapp_labelandmodelname of an installed model.GenericForeignKey: Defined indjango.contrib.contenttypes.fields, this field allows a model to point to an instance of any other model. It requires two local fields: one to store theContentTypeID and another to store the object's primary key.GenericRelation: Also indjango.contrib.contenttypes.fields, this provides a reverse relationship to aGenericForeignKey, enabling lookups and ensuring that related objects are handled correctly during deletion.
Implementation Example
In tests/admin_filters/models.py, a tagging system is implemented using these components:
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models
class TaggedItem(models.Model):
tag = models.SlugField()
# Field to store the type of the related object
content_type = models.ForeignKey(
ContentType, models.CASCADE, related_name="tagged_items"
)
# Field to store the ID of the related object
object_id = models.PositiveIntegerField()
# The actual generic relation
content_object = GenericForeignKey("content_type", "object_id")
class Bookmark(models.Model):
url = models.URLField()
# Reverse relation to allow bookmark.tags.all()
tags = GenericRelation(TaggedItem)
Key Considerations
- Deletion:
GenericForeignKeydoes not support database-levelON DELETE CASCADE. You must useGenericRelationon the target model to ensure that related generic objects are deleted when the target is removed. - Querying: You cannot filter directly on a
GenericForeignKeyin afilter()call. You must filter using thecontent_typeandobject_idfields or use theGenericRelationif defined.
PostgreSQL Extensions
The django.contrib.postgres module provides features specific to PostgreSQL, most notably advanced full-text search.
Full-Text Search with SearchVector
The SearchVector class allows you to combine multiple fields into a single searchable index. This is often used with annotate() to perform complex searches across different model attributes.
Example from tests/postgres_tests/test_search.py:
from django.contrib.postgres.search import SearchVector, SearchQuery
# Searching across multiple fields (scene setting and dialogue)
searched = Line.objects.annotate(
search=SearchVector("scene__setting", "dialogue"),
).filter(search="elbows")
Ranking and Weighting
For more sophisticated search results, SearchRank can be used to order results by relevance. You can also assign weights ('A', 'B', 'C', 'D') to different fields in a SearchVector to prioritize matches in specific columns.
from django.contrib.postgres.search import SearchRank, SearchVector, SearchQuery
vector = SearchVector("dialogue", weight="A") + SearchVector("character__name", weight="D")
query = SearchQuery("witch")
# Rank results based on the weighted vector
results = Line.objects.annotate(
rank=SearchRank(vector, query)
).order_by("-rank")
GeoDjango (GIS)
GeoDjango, located in django.contrib.gis, extends the ORM to support spatial data types and operations. It allows for storing geographic coordinates and performing spatial queries like "find all points within a certain radius."
Spatial Fields
GeoDjango provides specialized field types in django.contrib.gis.db.models.fields that correspond to OpenGIS geometry types:
PointField: Stores a single pair of coordinates.LineStringField: Stores a sequence of points forming a line.PolygonField: Stores a sequence of points forming a closed shape.MultiPolygonField: Stores a collection of polygons.
Configuration Requirements
To use GeoDjango, the database engine must be set to a spatial backend in settings.py, such as:
django.contrib.gis.db.backends.postgisdjango.contrib.gis.db.backends.mysqldjango.contrib.gis.db.backends.spatialite
Additionally, system-level libraries like GEOS, GDAL, and PROJ must be installed on the host machine.
Sitemaps
The sitemaps framework in django.contrib.sitemaps automates the generation of XML sitemaps to help search engines index your site effectively.
The Sitemap Class
You create a sitemap by subclassing Sitemap and defining the items() method. By default, it uses the get_absolute_url() method on the objects returned by items().
from django.contrib.sitemaps import Sitemap
class MyModelSitemap(Sitemap):
changefreq = "never"
priority = 0.5
def items(self):
return MyModel.objects.filter(is_public=True)
def lastmod(self, obj):
return obj.updated_at
GenericSitemap
For simple cases, GenericSitemap in django.contrib.sitemaps/__init__.py can be used to generate a sitemap directly from a queryset without writing a custom class:
from django.contrib.sitemaps import GenericSitemap
from myapp.models import Entry
info_dict = {
"queryset": Entry.objects.all(),
"date_field": "pub_date",
}
sitemaps = {
"blog": GenericSitemap(info_dict, priority=0.6),
}
Dependencies
The sitemap framework typically depends on django.contrib.sites to determine the domain name for URLs. If the sites framework is not installed, you must provide a Site or RequestSite object manually when rendering the sitemap view.