/django-generic-links

🗂️ Django application for associating links + metadata to any model instance

Primary LanguagePythonOtherNOASSERTION

django-generic-links

Python Compatibility PyPi Version CI badge codecov License Python Compatibility PyPi Version CI badge codecov License

Simple app to attach links to any Django model. Compatible with Django 4.x to 5.0 and Python 3.9 to 3.12.

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 .

then add generic_links to your settings.py:

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

then run the migrations:

python manage.py migrate

and 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

Using django-generic-links models

>>> 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>]>

Generic Links Inline Admin

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]

Using django-generic-links templatetags

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 %}

<hl>{{ artist.name }}</hl>
<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>

Contributing

Contributions are welcome! ❤️

Please read Contributing.md for detailed instructions on how to help.

Running Tests

hatch run test:test will run the tests in every Python + Django versions combination.

hatch run test.py3.12-5.0:test will run them for python 3.12 and Django 5.0. Please see possible combinations using hatch env show` ("test" matrix).

License

django-generic-links is released under an BSD License - see the LICENSE file for more information.

Acknowledgements

Develop & built using Hatch project linting - Ruff code style - black

Tools used in building this package:

Posts I learned from: