Skip to main content

django-friendship

CI PyPI Python versions Django versions

This application enables you to create and manage follows, blocks and bi-directional friendships between users. It features:

  • Friendship request objects that can be accepted, rejected, canceled, or marked as viewed.
  • Hooks to easily list all friend requests sent or received by a given user, filtered by the status of the request.
  • A blocklist for each user of users they've blocked.
  • Tags to include information about friendships, blocks and follows in your templates.
  • Integration with AUTH_USER_MODEL.
  • Validation to prevent common mistakes.
  • Faster server response time through caching

Requirements

Django 5.2, 6.0, and 6.1 + Python 3.11, 3.12, 3.13, 3.14, and 3.15 (including free-threaded 3.14t and 3.15t) since v1.12.0.

Previously:

  • Django 4.2, 5.0, 5.1, 5.2, 6.0, and 6.1 + Python 3.10–3.14 since v1.10.0 (3.15 tested as a pre-release from v1.11.1)
  • Django 4.2, 5.1, 5.2 + Python 3.9–3.13 since v1.9.6

Installation

  1. pip install django-friendship
  2. add "friendship" to INSTALLED_APPS and run python manage.py migrate.
  3. Use the friendship manager in your own views, or wire up the URLconf to include the builtin views:
urlpatterns = [
    # other paths
    path("friendship/", include("friendship.urls"))
]

Usage

django-friendship provides a free API that gives you several ways to create and manage friendship requests or follows in your views. Add the following at the top of your views.py:

from django.contrib.auth.models import User
from friendship.models import Friend, Follow, Block

Getting Data about Friendships

  • List all of a user's friends: Friend.objects.friends(user=request.user)
  • Count of a user's friends: Friend.objects.friend_count(user=request.user)
  • List all unread friendship requests: Friend.objects.unread_requests(user=request.user)
  • List all unrejected friendship requests: Friend.objects.unrejected_requests(user=request.user)
  • Count of all unrejected friendship requests: Friend.objects.unrejected_request_count(user=request.user)
  • List all rejected friendship requests: Friend.objects.rejected_requests(user=request.user)
  • List of all sent friendship requests: Friend.objects.sent_requests(user=request.user)
  • Test if two users are friends: Friend.objects.are_friends(user1=request.user, user2=other_user) == True
  • Test if a friendship request already exists between two users (either direction): Friend.objects.request_exists(from_user=request.user, to_user=other_user) == True

Getting Data about Follows

  • List of a user's followers: Follow.objects.followers(user=request.user)
  • List of who a user is following: Follow.objects.following(user=request.user)

Getting Data about Blocks

  • List of a user's blockers: Block.objects.blocked(user=request.user)
  • List of who a user is blocking: Block.objects.blocking(user=request.user)
  • Test if a user is blocked: Block.objects.is_blocked(user1=request.user, user2=other_user) == True

Managing Friendships and Follows

See the cookbook for more task-oriented recipes.

Create a friendship request:

other_user = User.objects.get(pk=1)
Friend.objects.add_friend(
    from_user=request.user,  # The sender
    to_user=other_user,  # The recipient
    message="Hi! I would like to add you",  # optional
)

Let the user who received the request respond:

from friendship.models import FriendshipRequest

friend_request = FriendshipRequest.objects.get(
    from_user=request.user, to_user=other_user
)
friend_request.accept()
# or friend_request.reject()

A rejected request does not block future requests — the sender may request again later. To cap how many friends a user can have, see FRIENDSHIP_MAX_FRIENDS under Settings.

To remove the friendship relationship between request.user and other_user, do the following:

Friend.objects.remove_friend(from_user=request.user, to_user=other_user)

Make request.user a follower of other_user:

Follow.objects.add_follower(follower=request.user, followee=other_user)

Make request.user block other_user:

Block.objects.add_block(blocker=request.user, blocked=other_user)

Make request.user unblock other_user:

Block.objects.remove_block(blocker=request.user, blocked=other_user)

Templates

You can use django-friendship tags in your templates. First enter:

{% load friendshiptags %}

Then use any of the following:

{% friends request.user %}
{% followers request.user %}
{% following request.user %}
{% friend_requests request.user %}
{% blockers request.user %}
{% blocking request.user %}

Signals

django-friendship emits the following signals (from friendship.signals):

  • friendship_request_created
  • friendship_request_rejected
  • friendship_request_canceled
  • friendship_request_viewed
  • friendship_request_accepted
  • friendship_removed
  • follower_created
  • follower_removed
  • followee_created
  • followee_removed
  • following_created
  • following_removed
  • block_created
  • block_removed

Each signal's sender is the emitting model, so you can connect a receiver scoped to it:

from django.dispatch import receiver

from friendship.models import Follow
from friendship.signals import follower_created


@receiver(follower_created, sender=Follow)
def on_follow(sender, follower, **kwargs):
    ...

Settings

django-friendship supports the following settings:

FRIENDSHIP_CONTEXT_OBJECT_NAME = "user"
FRIENDSHIP_CONTEXT_OBJECT_LIST_NAME = "users"
FRIENDSHIP_MANAGER_FRIENDSHIP_REQUEST_SELECT_RELATED_STRATEGY = (
    "select_related"  # ('select_related', 'prefetch_related', 'none')
)

# Optional cap on the number of friends each user may have. Unset (the
# default) means unlimited, so existing projects are unaffected. When set,
# accepting a request that would put either user over the limit raises
# friendship.exceptions.MaxFriendsExceededError.
FRIENDSHIP_MAX_FRIENDS = 800

Limiting the number of friends

By default a user may have unlimited friends. Set FRIENDSHIP_MAX_FRIENDS to cap it. The limit is checked when a request is accepted — if either user is already at the limit, accept() raises MaxFriendsExceededError and no friendship is created (the request is left intact so it can be accepted later, e.g. after removing another friend):

from friendship.exceptions import MaxFriendsExceededError

try:
    friend_request.accept()
except MaxFriendsExceededError:
    ...  # tell the user their friend list is full

# You can check a user's current friend count directly:
Friend.objects.friend_count(user=request.user)

Custom user models

django-friendship works with a custom AUTH_USER_MODEL. The bundled views and templates resolve users by your user model's USERNAME_FIELD (via get_username()), so a model that authenticates by, say, email works out of the box — the value captured in the friendship URLs is looked up against USERNAME_FIELD. For the default user model this is username, so nothing changes.

Contributing

Development takes place on GitHub. Bug reports, patches, and fixes are always welcome!

Need help?

REVSYS can help with your Python, Django, and infrastructure projects. If you have a question about this project, please open a GitHub issue. If you love us and want to keep track of our goings-on, here's where you can find us online:

Metadata

Release files for django-friendship 1.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-friendship 1.12.0
File Size Uploaded
django_friendship-1.12.0.tar.gz 25.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-friendship 1.12.0
File Interpreter ABI Platform
django_friendship-1.12.0-py3-none-any.whl Python 3 none any Details

Total release size: 64.5 kB

Release files / django_friendship-1.12.0.tar.gz

Download URL django_friendship-1.12.0.tar.gz
Size 25.0 kB
Tags Source
SHA-256 checksum
How to use checksums
54b4772efd297ec2d208abc35584901fcf4d51dff7f6e6b38235f588d3d64aae
BLAKE2b-256 checksum
How to use checksums
7e186af1b17021806b65d33d8d25ecec9d2bb41715a917e2b89cdc588b69316b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / django_friendship-1.12.0-py3-none-any.whl

Download URL django_friendship-1.12.0-py3-none-any.whl
Size 39.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5c6024231f19630f8d335038fffba43d27cc8f464871a2e3c7921a88e555571d
BLAKE2b-256 checksum
How to use checksums
bd6814a8d152fea27bf5a0fb7aa9b9781bc330ac0cc3581b7dda0be7d2aae4b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

1.12.0 This release

2 release files

1.11.0

2 release files

1.10.0

2 release files

1.9.6

2 release files

1.9.5

2 release files

1.9.4

1 release file

1.9.3

1 release file

1.9.2

2 release files

1.9.1

2 release files

1.9.0

2 release files

1.8.2

1 release file

1.8.1

1 release file

1.8.0

1 release file

1.7.1

1 release file

1.7.0

1 release file

1.6.0

1 release file

1.5.0

1 release file

1.3.3

1 release file

1.3.2

1 release file

1.3.1

1 release file

1.3.0

1 release file

1.2.0

1 release file

1.1.0

1 release file

1.0.0

1 release file

0.9.0

1 release file

0.8.3

1 release file

0.8.1

1 release file

0.8.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page