Skip to content

Getting started with django-generic-links

Python Compatibility Django Compatibility PyPi Version CI badge codecov License

Simple and generic application for Django projects to attach and handle links for any object. Compatible with Django 4.2 to 5.2 and Python 3.10 to 3.14.

Features

  • Model for creating generic link relations
  • Reverse Generic Relation (Django) for your models
  • Model Admin
  • Generic inline admin to manage any model's generic links
  • A template tag to get all links for a given model instance
  • A fully working example project

Installation

Via pip command:

pip install django-generic-links

...or you can clone the repo and install it using pip too:

git clone git://github.com/matagus/django-generic-links.git
cd django-generic-links
pip install -e .

Quick Start

Add generic_links to your INSTALLED_APPS in settings.py:

INSTALLED_APPS = (
    # ...
    "generic_links",
    # ...
)

Then run the migrations:

python manage.py migrate

Finally, add the reverse generic relation to each of the models you're going to add generic links to:

from django.db import models
from django.contrib.contenttypes.fields import GenericRelation


class Artist(models.Model):
    name = models.CharField(max_length=100)
    bio = models.TextField()

    # This is important so that we can get the GenericLink related instances for an object of this model
    generic_links = GenericRelation("generic_links.GenericLink")


class Album(models.Model):
    title = models.CharField(max_length=100)
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    release_date = models.DateField(null=True, blank=True)

    generic_links = GenericRelation("generic_links.GenericLink")

Usage

>>> from generic_links.models import GenericLink
>>> from music.models import Artist
>>>
>>> # Get an artist from the database...
>>> lou_reed = Artist.objects.get(pk=1)
>>> lou_reed
<Artist: Lou Reed>
>>>
>>> # Create the first link
>>> link1 = GenericLink(title="Wikipedia Page", url="http://en.wikipedia.org/wiki/Lou_Reed", content_object=lou_reed)
>>> link1.save()
>>>
>>> # and then a second one
>>> link2 = GenericLink(title="Encyclopaedia Britannica", url="https://www.britannica.com/biography/Lou-Reed",
content_object=lou_reed)
>>> link2.save()
>>>
>>> # Now get all the links for the artist object:
>>> lou_reed.generic_links.all()
<QuerySet [<GenericLink: Encyclopaedia Britannica :: https://www.britannica.com/biography/Lou-Reed>,
<GenericLink: Wikipedia Page :: https://en.wikipedia.org/wiki/Lou_Reed>]>

Since a GenericLink instance will be associated to another object you usually wish to show an inline model admin form in that model form.

from django.contrib import admin

from generic_links.admin import GenericLinkStackedInline

from music_app.models import Artist


@admin.register(Artist)
class ArtistAdmin(admin.ModelAdmin):
    # ...
    inlines = [GenericLinkStackedInline]

Now imagine you have an artist page. You're passing artist object using template context and you want to get all the links for it:

{% load generic_links_tags %}

<h1>{{ artist.name }}</h1>
<p>{{ artist.description }}</p>
<h2>Links for {{ artist.name }}</h2>
{% get_links_for artist as artist_links %}
<ul>
{% for link in artist_links %}
  <li><a href="{{ link.url }}" title="{{ link.title }}">{{ link.title }}</a></li>
{% endfor %}
</ul>

Running Tests

Prerequisites: Install Hatch if not already installed: pip install hatch

List available test environments:

hatch env show test

Run all tests (all Python + Django combinations):

hatch run test:test

Run tests for specific Python/Django version:

hatch run test.py3.14-5.2:test  # Python 3.14 + Django 5.2
hatch run test.py3.13-5.1:test  # Python 3.13 + Django 5.1

Run specific test file:

hatch run test.py3.13-5.2:test tests.test_models

Coverage:

hatch run test:cov  # Run tests with coverage report

Troubleshooting: If you encounter environment issues, clean and rebuild: hatch env prune