Code Monkey home page Code Monkey logo

django-friendship's Introduction

django-friendship

CI

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 3.2 since v1.9.1 **

Previously: Django 1.11+ since v1.7.0 (latest release supporting Django 1.10 is v1.6.0)

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 = [
    ...
    path('friendship/', include('friendship.urls'))
    ...
]

Note: If you are migrating from django-friendship v1.6.x, you'll need to rollback your migrations and fake migration 0002

$ ./manage.py migrate friendship 0001
$ ./manage.py migrate friendship 0002 --fake

If you're migrating from v1.7.x, you'll likely have to fake 0003 as well:

$ ./manage.py migrate friendship 0003 --fake

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(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)
  • Count of all rejected friendship requests: Friend.objects.rejected_request_count(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(request.user, other_user) == True

Getting Data about Follows

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

Getting Data about Blocks

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

Managing Friendships and Follows

Create a friendship request:

other_user = User.objects.get(pk=1)
Friend.objects.add_friend(
    request.user,                               # The sender
    other_user,                                 # The recipient
    message='Hi! I would like to add you')      # This message is 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()

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

Friend.objects.remove_friend(request.user, other_user)

Make request.user a follower of other_user:

Follow.objects.add_follower(request.user, other_user)

Make request.user block other_user:

Block.objects.add_block(request.user, other_user)

Make request.user unblock other_user:

Block.objects.remove_block(request.user, 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:

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

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')

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:

django-friendship's People

Contributors

acjh avatar adamyala avatar afnarel avatar awidgery avatar dependabot[bot] avatar drager avatar dyachoksa avatar econner avatar evgkirov avatar fcurella avatar fdemmer avatar frankwiles avatar hisham-pak avatar jacobb avatar jefftriplett avatar julianwachholz avatar komarserjio avatar mayank6 avatar nikosmichas avatar ppp23 avatar predatell avatar pritamsoni-hsr avatar recall704 avatar shashkin avatar tijs avatar timgates42 avatar tjcrowley avatar umbertov avatar uri-rodberg avatar yurtaev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-friendship's Issues

Friend request when users are already friends

add_friend() currently creates a friend request even when the users are already friends. Attempting to then accept() the friend request generates errors.

I added the following to line 227 of models.py to prevent creation of the superfluous friend request:

if self.are_friends(from_user, to_user):
    raise AlreadyExistsError("Already friends")

I'm a bit of a newbie so not quite sure how to submit a pull request, but I could try and figure it out if this is a desired change!

no module named defaults using django 1.10

I GOT THIS ERROR:

ImportError: No module named defaults.......friendships\urls.py in line 4

I changed the urls.py file with the code below:

`try:
from django.conf.urls import url, include
except ImportError:
from django.conf.urls import url, include
from friendship.views import view_friends, friendship_add_friend, friendship_accept,
friendship_reject, friendship_cancel, friendship_request_list,
friendship_request_list_rejected, friendship_requests_detail, followers,
following, follower_add, follower_remove, all_users

urlpatterns = [
url(
regex=r'^users/$',
view=all_users,
name='friendship_view_users',
),
url(
regex=r'^friends/(?P[\w-]+)/$',
view=view_friends,
name='friendship_view_friends',
),
url(
regex=r'^friend/add/(?P<to_username>[\w-]+)/$',
view=friendship_add_friend,
name='friendship_add_friend',
),
url(
regex=r'^friend/accept/(?P<friendship_request_id>\d+)/$',
view=friendship_accept,
name='friendship_accept',
),
url(
regex=r'^friend/reject/(?P<friendship_request_id>\d+)/$',
view=friendship_reject,
name='friendship_reject',
),
url(
regex=r'^friend/cancel/(?P<friendship_request_id>\d+)/$',
view=friendship_cancel,
name='friendship_cancel',
),
url(
regex=r'^friend/requests/$',
view=friendship_request_list,
name='friendship_request_list',
),
url(
regex=r'^friend/requests/rejected/$',
view=friendship_request_list_rejected,
name='friendship_requests_rejected',
),
url(
regex=r'^friend/request/(?P<friendship_request_id>\d+)/$',
view=friendship_requests_detail,
name='friendship_requests_detail',
),
url(
regex=r'^followers/(?P[\w-]+)/$',
view=followers,
name='friendship_followers',
),
url(
regex=r'^following/(?P[\w-]+)/$',
view=following,
name='friendship_following',
),
url(
regex=r'^follower/add/(?P<followee_username>[\w-]+)/$',
view=follower_add,
name='follower_add',
),
url(
regex=r'^follower/remove/(?P<followee_username>[\w-]+)/$',
view=follower_remove,
name='follower_remove',
),
]
`

Custom field to relationship

Hi,
Is there possibility to add new field (fields) to relationship model? Could you give some advice? Thank you.

Version 1.7.1 - running "manage.py migrate" throws an exception (when upgrading from 1.5.0).

Running migrations:
Applying friendship.0002_auto_20180705_1444...Traceback (most recent call last):
File ".venv\lib\site-packages\django\db\backends\utils.py", line 64, in execute
return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: relation "friendship_block" does not exist

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "speedy\net\manage.py", line 14, in
execute_from_command_line(sys.argv)
File ".venv\lib\site-packages\django\core\management_init_.py", line 364, in execute_from_command_line
utility.execute()
File ".venv\lib\site-packages\django\core\management_init_.py", line 356, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File ".venv\lib\site-packages\django\core\management\base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File ".venv\lib\site-packages\django\core\management\base.py", line 330, in execute
output = self.handle(*args, **options)
File ".venv\lib\site-packages\django\core\management\commands\migrate.py", line 204, in handle
fake_initial=fake_initial,
File ".venv\lib\site-packages\django\db\migrations\executor.py", line 115, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File ".venv\lib\site-packages\django\db\migrations\executor.py", line 145, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File ".venv\lib\site-packages\django\db\migrations\executor.py", line 244, in apply_migration
state = migration.apply(state, schema_editor)
File ".venv\lib\site-packages\django\db\migrations\migration.py", line 129, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File ".venv\lib\site-packages\django\db\migrations\operations\models.py", line 536, in database_forwards
getattr(new_model._meta, self.option_name, set()),
File ".venv\lib\site-packages\django\db\backends\base\schema.py", line 369, in alter_unique_together
self.execute(self._create_unique_sql(model, columns))
File ".venv\lib\site-packages\django\db\backends\base\schema.py", line 136, in execute
cursor.execute(sql, params)
File ".venv\lib\site-packages\django\db\backends\utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File ".venv\lib\site-packages\django\db\backends\utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File ".venv\lib\site-packages\django\db\utils.py", line 94, in exit
six.reraise(dj_exc_type, dj_exc_value, traceback)
File ".venv\lib\site-packages\django\utils\six.py", line 685, in reraise
raise value.with_traceback(tb)
File ".venv\lib\site-packages\django\db\backends\utils.py", line 64, in execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "friendship_block" does not exist

(With Django 1.11 or 2.0)

Self Friending

We want to be able to have ourselves in our list of friends. If I edit the code and undo / comment out the check for self friendship (line 232 in models.py) will this cause a problem anywhere else in the code?

Add an optional MAX_NUMBER_OF_FRIENDS_ALLOWED in settings

In some websites the maximal number of friends is limited. You can add an optional MAX_NUMBER_OF_FRIENDS_ALLOWED in settings. If it's not defined then the number of friends is unlimited.

You can see for example on Speedy Net, where I defined MAX_NUMBER_OF_FRIENDS_ALLOWED = 800. I'm currently working on branch uri_merge_with_master_2018-12-28_a and you can see my latest code there:

https://github.com/speedy-net/speedy-net/tree/uri_merge_with_master_2018-12-28_a

(The code using this setting is mainly used in class LimitMaxFriendsMixin on https://github.com/speedy-net/speedy-net/blob/uri_merge_with_master_2018-12-28_a/speedy/core/friends/views.py).

Current (most up-to-date) links:
https://github.com/speedy-net/speedy-net/tree/staging
https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/friends/views.py

Question about naming model Friend and its fields

Hello!
To be honest, I'm confused, why did you name model for representing friendship between two users like "Friend". For me, "Friendship" is more proper name for that.
What do "user_to" and "user_from" mean? I understand how this app works, but I can't get used to these names of fields.

What the right way to think of name of that model and its fields?

DRF support

Trying to use generics.ListCreateAPIView

For
self.queryset = Follow.objects.following(request.user)

I keep getting:
django list object has no attribute order_by

Follow.objects.following(request.user) works fine when directly adding to Serializer, but I would like to use ListAPIView Pagination for endless list.

Handling Edge Cases

There are a lot of edge cases that it would be awesome for this library to handle.

  1. Sending multiple friend requests (should do nothing, or just update the time created)
  2. Friend Request A->B then Friend Request B->A should accept A's friend request
  3. Self friending - this should be an option.
  4. You are still able to create friend requests even after you are friend with that person.

Also what is the correct way to accept a friend request. In the intro docs I see

### Managing friendship relationships
    other_user = User.objects.get(pk=1)
    new_relationship = Friend.objects.add_friend(request.user, other_user)
    Friend.objects.are_friends(request.user, other_user) == True

which implies that add_friend adds a friendship, but it actually sends a friend request. There's an accept function on the friend request class - I'm assuming that we use this one?

A bit more explanation would be super helpful to get started learning how to use the library - looks good otherwise - thanks for creating this!

PyPI version out of date

Hi, I initially tried installing from PyPI with pip install django-friendship and ended up with an older version of this app (and my initial db migration failed because I'm using a custom user model, which was addressed in a more recent release).

This gave me an opportunity to learn how to install directly from github using pip. So that was cool and I'm all set now, but just thought I'd let you guys know!

In any case, thanks for the app. Looks extremely helpful.

A user is able to add themselves as a friends which triggers a 500 error

Hello, I've been looking into using this package in production and I have a few questions about its inner workings... First off, I've noticed that users can add themselves as friends - this isn't really a problem except for the fact that it will trigger the following integrity error: columns from_user_id, to_user_id are not unique. I've been wondering about how to best go about preventing users from adding themselves as friends and causing things to blow up. I'm of the opinion that this should probably be written into the views, but would also be plausible to prevent this with some validation in the template (although this wouldn't stop people from playing with the URLs). Below is a bit of basic validation that I quickly wrote in to the friendship_add_friend view. If you think that this is a suitable means of validation, I'm happy to go ahead and tweak the views (with proper redirects) and make same changes to the templates so that users shouldn't arrive at this point anyway.

@login_required
def friendship_add_friend(request, to_username, template_name='friendship/friend/add.html'):
    """ Create a FriendshipRequest """
    if request.method == 'POST':
        to_user = user_model.objects.get(username=to_username)
        from_user = request.user
        if from_user == to_user:
            return redirect('/')
        else:
            Friend.objects.add_friend(from_user, to_user)
            return redirect('friendship_request_list')

    return render(request, template_name, {'to_username': to_username})

The other thing I noticed is that the friendship_request_list shows all friend requests from all users. Is there any particular reason that you've commented out the line that only shows requests that belong to the current user?

Blocking features

I've written in a Block User feature that is like the opposite of Followers. Would you be interested in this?

Reversed arguments in Friend.objects.remove_friend()

The remove_friend method uses a query to check for friend requests in both directions with the from_user and to_user arguments. But unlike the other methods, that have a method signature like this:
Friend.objects.add_friend(from_user, to_user)
remove_friend's method signature looks like this:
Friend.objects.remove_friend(to_user, from_user)
I don't see that reversing the order of the arguments from the norm serves any purpose in this case. If you agree I'll submit a PR.

Bug in BlockManager

Currently, the documentation says that the list of a user's blockers can be obtained as follows:

Block.objects.blockers(request.user)

However, there is no blockers function in BlockManager. When I looked at the code, I've seen a blocked function that should suppose to do that. This function is below:

def blocked(self, user):
        """ Return a list of all blocks """
        key = cache_key('blocked', user.pk)
        blocked = cache.get(key)

        if blocked is None:
            qs = Block.objects.filter(blocked=user).all()
            blocked = [u.blocked for u in qs]
            cache.set(key, blocked)

        return blocked

As seen it first filters Block objects with blocked=user, then takes u.blocked for every u in qs. As a result, we obtain a list consisting of users. Instead, a list consisting of u.blockers should be returned.

Bulk insert

Is it possible to bulk insert followers/follow

In my use case I start following all Facebook friends on application start.
I use this method : Follow.objects.add_follower(self.request.user, followee)

Greetings Markus

Friendship Cache

I'm using the REST Api using the DRF to send friend requests, accept friend requests, and get all friends. After I accept the friend request, I immediate pull all friends for that user; however, it doesn't show the updated list of friends. After a couple of seconds, it finally updates with the actual results. At the same time, when I look at the django admin, it looks like the friends have already been updated pretty instantaneously. I don't think this is an issue with the django-friendship code, but I'm not really sure what's going on. Any help would be greatly appreciated. Thanks!

Proper way to remove sent request between two users?

I'm trying to properly remove a sent friend request between two users. (Friendship is in request state still, not complete)

If I simply delete the FriendshipRequest: FriendshipRequest.objects.filter(from_user=request.user, to_user=user).delete()

The cache is not cleared. It appears I need to call bust_cache('sent_requests', from_user.pk) after this to be able to get an properly updated list of sent friend requests.

However, it appears that bust_cache is not available to FriendshipManager.

What is the appropriate way to remove a sent requests where the sent_requests cache is properly updated?

My workaround for this is to not test the contents of the sent_requests list, and instead query FriendRequests directly.

IntegrityError

After testing out django friendship, I'm getting this error:

                           IntegrityError at /pal/

             (1062, "Duplicate entry '1-1' for key 'from_user_id'")

                        Request Method:     GET
                        Request URL:    http://127.0.0.1:8000/pal/
                        Django Version:     1.3.1
                        Exception Type:     IntegrityError
                        Exception Value:    

                       (1062, "Duplicate entry '1-1' for key 'from_user_id'")

                          Exception Location:   C:\Python27\lib\site-packages\MySQLdb\connections.py in defaulterrorhandler, line 36
                        Python Executable:  C:\Python27\python.exe
                        Python Version:     2.7.2

Views.py:

         def my_pal(request):
                  #list of this users friends
                  all_friends=Friend.objects.friends(request.user)

                   #list all unread friendship requests
                    requests=Friend.objects.unread_requests(user=request.user)
                  #list all rejected friendship requests.
                   rejects=Friend.objects.rejected_requests(user=request.user)
                  #list of this user's followers
                  #all_followers=Follow.objects.followers(request.user)
                  #list of who this user is following
                 #following=Follow.objects.following(request.user)
                 ###Managing friendship relationship
                 other_user=User.objects.get(pk=1)
                 new_relationship=Friend.objects.add_friend(request.user, other_user)
                 Friend.objects.are_friends(request.user, other_user)==True
                 Friend.objects.remove_friend(other_user, request.user)
               #Create request.user follows other_user relationship
               following_created=Follow.objects.add_follower(request.user, other_user)
              return render_to_response('frndz.html',{'Friend': Friend},context_instance=RequestContext(request))

What I'm I doing wrong?

Is can_request_send method correct?

The code below seems to check if request can be sent from 'from_user' to 'to_user'

    def can_request_send(self, from_user, to_user):
        """ Checks if a request was sent """
        if from_user == to_user or FriendshipRequest.objects.filter(
            from_user=from_user,
            to_user=to_user,
            ).exists() is False:
            return False
        else: 
            return True

The method returns False when the request from 'from_user' to 'to_user' has NOT been made yet, which seems to be opposite.
Should is False be changed to is True ?

https://github.com/revsys/django-friendship/blob/master/friendship/models.py

Signals not working for Follow model, potentially others as well.

I am using Python 3.7.1, Django 2.0.9
This issue apparently was mentioned, but haven't seen any changes to deal with it.

I am trying to use the following signals follower_created, followee_created, following_created.

I connected it like this

@receiver([follower_created, followee_created, following_created], sender=Follow)
def on_following_created(sender, **kwargs):
    print('on_following_created')
    print(kwargs)

I was able to get it to work by changing how the signals were being triggered in the models.py

follower_created.send(sender=self, follower=follower)
followee_created.send(sender=self, followee=followee)
following_created.send(sender=self, following=relation)

to

follower_created.send(sender=self.model, follower=follower)
followee_created.send(sender=self.model, followee=followee)
following_created.send(sender=self.model, following=relation)

assuming the ideal usage:

@receiver(..., sender=Follow)

is for sender to be the model.

Without making any changes to how the signals are triggered.
Connecting would just be

@receiver(..., sender=Follow.objects) # looks weird, but works (not sure intentional usage)

I have not checked the other signals, but I believe any signal being triggered as .send(sender=self) should be changed to .send(sender=self.model).

Edit:

I also tried with follower_removed, followee_removed, following_removed and it does not work with the following connection

@receiver([follower_removed, followee_removed, following_removed], sender=Follow)
def deleteFollowNotification(sender, **kwargs):
    print('deleteFollowNotification')
    print(kwargs)

I had to change

follower_removed.send(sender=rel, follower=rel.follower)
followee_removed.send(sender=rel, followee=rel.followee)
following_removed.send(sender=rel, following=rel)

to

follower_removed.send(sender=rel._meta.model, follower=rel.follower)
followee_removed.send(sender=rel._meta.model, followee=rel.followee)
following_removed.send(sender=rel._meta.model, following=rel)
@receiver([follower_removed, followee_removed, following_removed], sender=Follow.objects) # using Follow.objects

doesn't work either.

in models.py

rel = Follow.objects.get(follower=follower, followee=followee)

is an instance and I have no way of triggering follower_removed, followee_removed, following_removed.

Either sender in .send(sender=MyModel) needs to always be the model class or I am using these signals incorrectly.

I have checked Django release notes and haven't found anything that would change how signals work.

friendship_request_canceled cause TypeError: Model instances without primary key value are unhashable

I've come across an issue:

django: 2.2.3
django-friendship: 1.8.1

Traceback:

2019-10-24 12:57:57 [ERROR] Internal Server Error: /v1/friendship_requests/11/cancel/
Traceback (most recent call last):
 File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
 response = get_response(request)
 File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
 response = self.process_exception_by_middleware(e, request)
 File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
 response = wrapped_callback(request, *callback_args, **callback_kwargs)
 File "/usr/local/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
 return view_func(*args, **kwargs)
 File "/usr/local/lib/python3.7/site-packages/rest_framework/viewsets.py", line 116, in view
 return self.dispatch(request, *args, **kwargs)
 File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 495, in dispatch
 response = self.handle_exception(exc)
 File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 455, in handle_exception
 self.raise_uncaught_exception(exc)
 File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 492, in dispatch
 response = handler(request, *args, **kwargs)
 File "./api_v1/viewsets/friendship_requests.py", line 105, in cancel
 instance.cancel()
 File "/usr/local/lib/python3.7/site-packages/friendship/models.py", line 157, in cancel
 friendship_request_canceled.send(sender=self)
 File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 170, in send
 if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
 File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 536, in __hash__
 raise TypeError("Model instances without primary key value are unhashable")
TypeError: Model instances without primary key value are unhashable

I think the problem occurs because we generate signal friendship_request_canceled when we've already deleted that object.

    def cancel(self):
        """ cancel this friendship request """
        self.delete()
        friendship_request_canceled.send(sender=self)
        bust_cache("requests", self.to_user.pk)
        bust_cache("sent_requests", self.from_user.pk)
        return True

deleting a user

hi,
whenever a user is deleted in the admin it brings rise to an error due to the existing relationships involving the given user

Support Django 2.0

I tried to upgrade Django to 2.0.1 and received an exception from django-friendship:

lib\site-packages\friendship\models.py", line 73, in FriendshipRequest
from_user = models.ForeignKey(AUTH_USER_MODEL, related_name='friendship_requests_sent')
TypeError: init() missing 1 required positional argument: 'on_delete'

Can you please fix to support Django 2.0?

send signals after db is affected

friendship_request_canceled is send after delete -> db is affected
friendship_request_rejected is send before save -> db is not affected yet
friendship_request_viewed is send before save -> db is not affected yet

Database Error

When i run initial migrations of my system, i get the error:

Running migrations for friendship:

  • Migrating forwards to 0001_initial.

    friendship:0001_initial
    FATAL ERROR - The following SQL query failed: ALTER TABLE "friendship_friendshiprequest" ADD CONSTRAINT "from_user_id_refs_id_fb58c409" FOREIGN KEY ("from_user_id") REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED;
    The error was: relation "auth_user" does not exist

Error in migration: friendship:0001_initial
DatabaseError: relation "auth_user" does not exist

0002 migration file is missing

Referring the changes done in https://github.com/revsys/django-friendship/blame/91af0116d05a9ff2dd940ea9fa3dcf20a9ebac3a/friendship/models.py#L576, the corresponding migration file is not yet added with the codebase. The following migration is being created when I run makemigrations on my local

# -*- coding: utf-8 -*-
# Generated by Django 1.11.13 on 2018-05-26 18:08
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('friendship', '0001_initial'),
    ]

    operations = [
        migrations.AlterModelOptions(
            name='block',
            options={'verbose_name': 'Blocker Relationship', 'verbose_name_plural': 'Blocked Relationships'},
        ),
        migrations.AlterField(
            model_name='block',
            name='blocked',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blockees', to=settings.AUTH_USER_MODEL),
        ),
        migrations.AlterUniqueTogether(
            name='block',
            unique_together=set([('blocker', 'blocked')]),
        ),
    ]

Warning

manager.py:202: DeprecationWarning: The "depth" keyword argument has been deprecated.

Migration warning

Hi, just wanted to let you guys know about the following deprecation warning when running migrate or makemigrations on Django 1.7. It also appears on each restart of the Django development server.

$ ./manage.py makemigrations
/Users/alexington/.virtualenvs/project/lib/python2.7/site-packages/friendship/migrations/0001_initial.py:14: RemovedInDjango18Warning: Options.module_name has been deprecated in favor of model_name
  user_model_label = '%s.%s' % (User._meta.app_label, User._meta.module_name)

Thanks for the helpful app.

Use better __str__ for the admin interface

Hi,

I had to modify __str__ methods for the admin interface. Currently I'm using:

class Friend:
    def __str__(self):
        return "User {} is friends with {}".format(self.to_user, self.from_user)

class FriendshipRequest:
    def __str__(self):
        return "Friendship request from user {} to {}".format(self.from_user, self.to_user)

You might want to update the __str__ methods in your own models.

(We are not using your Block and Follow models).

unrejected_requests

Hi everyone,

I am currently implementing friendship functionality using django-friendship and I was wondering why the FriendshipManager has no function to get unrejected friendship requests (like unrejected_requests).

There are functions to get all requests, unread requests, read requests, and rejected requests. But unrejected requests are missing. This function would be particularly useful to display the relevant requests to the user which are not rejected. In addition there should be another function called unrejected_request_count (similar to unread_request_count).

I implemented this myself using this

qs = FriendshipRequest.objects.select_related(depth=1).filter(
to_user=user,
rejected__isnull=True).all()

but I would prefer a function integrated into the app. I could do this myself and create a pull request, if you guys think this makes sense. I don't get why nobody asked this before because I assume everyone needs this..

Why bother to use a post form to do the friendship_add_friend job?

in friendship_add_friend() from views.py, that is only one argument 'to_username' to pass, then the next step from this part of code introduced a form submit step to do the request as a friend job. it seems like a little redundant.
Couldn't that just be a one-step work?

Use USERNAME_FIELD

Sugestion: use USERNAME_FIELD instead of the attribute "username". If the model "User" is overwritten, this may not work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.