Skip to content

Commit e9ad8fa

Browse files
committed
Refactoring the querying API to in general denote when symmetrical
relationship are to be used by passing in a keyword arg (rather than separate methods)
1 parent 714d845 commit e9ad8fa

File tree

1 file changed

+87
-48
lines changed

1 file changed

+87
-48
lines changed

relationships/models.py

Lines changed: 87 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,20 @@ def __init__(self, instance=None, *args, **kwargs):
7878
super(RelationshipManager, self).__init__(*args, **kwargs)
7979
self.instance = instance
8080

81-
def add(self, user, status=None):
81+
def add(self, user, status=None, symmetrical=False):
82+
"""
83+
Add a relationship from one user to another with the given status,
84+
which defaults to "following".
85+
86+
Adding a relationship is by default asymmetrical (akin to following
87+
someone on twitter). Specify a symmetrical relationship (akin to being
88+
friends on facebook) by passing in :param:`symmetrical` = True
89+
90+
.. note::
91+
92+
If :param:`symmetrical` is set, the function will return a tuple
93+
containing the two relationship objects created
94+
"""
8295
if not status:
8396
status = RelationshipStatus.objects.following()
8497

@@ -88,82 +101,108 @@ def add(self, user, status=None):
88101
status=status,
89102
site=Site.objects.get_current()
90103
)
91-
92-
return relationship
93-
94-
def remove(self, user, status=None):
104+
105+
if symmetrical:
106+
return (relationship, user.relationships.add(self.instance, status, False))
107+
else:
108+
return relationship
109+
110+
def remove(self, user, status=None, symmetrical=False):
111+
"""
112+
Remove a relationship from one user to another, with the same caveats
113+
and behavior as adding a relationship.
114+
"""
95115
if not status:
96116
status = RelationshipStatus.objects.following()
97117

98-
return Relationship.objects.filter(
118+
res = Relationship.objects.filter(
99119
from_user=self.instance,
100120
to_user=user,
101121
status=status,
102122
site__pk=settings.SITE_ID
103123
).delete()
124+
125+
if symmetrical:
126+
return (res, user.relationships.remove(self.instance, status, False))
127+
else:
128+
return res
104129

105-
def get_relationships(self, status):
106-
return User.objects.filter(
130+
def _get_from_query(self, status):
131+
return dict(
107132
to_users__from_user=self.instance,
108133
to_users__status=status,
109-
to_users__site__pk=settings.SITE_ID
134+
to_users__site__pk=settings.SITE_ID,
110135
)
111136

112-
def get_related_to(self, status):
113-
return User.objects.filter(
137+
def _get_to_query(self, status):
138+
return dict(
114139
from_users__to_user=self.instance,
115140
from_users__status=status,
116141
from_users__site__pk=settings.SITE_ID
117142
)
118-
119-
def get_symmetrical(self, status):
120-
return User.objects.filter(
121-
to_users__status=status,
122-
to_users__from_user=self.instance,
123-
to_users__site__pk=settings.SITE_ID,
124-
from_users__status=status,
125-
from_users__to_user=self.instance,
126-
from_users__site__pk=settings.SITE_ID
127-
)
143+
144+
def get_relationships(self, status, symmetrical=False):
145+
"""
146+
Returns a QuerySet of user objects with which the given user has
147+
established a relationship.
148+
"""
149+
query = self._get_from_query(status)
150+
151+
if symmetrical:
152+
query.update(self._get_to_query(status))
153+
154+
return User.objects.filter(**query)
155+
156+
def get_related_to(self, status):
157+
"""
158+
Returns a QuerySet of user objects which have created a relationship to
159+
the given user.
160+
"""
161+
return User.objects.filter(**self._get_to_query(status))
128162

129163
def only_to(self, status):
164+
"""
165+
Returns a QuerySet of user objects who have created a relationship to
166+
the given user, but which the given user has not reciprocated
167+
"""
130168
from_relationships = self.get_relationships(status)
131169
to_relationships = self.get_related_to(status)
132170
return to_relationships.exclude(pk__in=from_relationships.values_list('pk'))
133171

134172
def only_from(self, status):
173+
"""
174+
Like :method:`only_to`, returns user objects with whom the given user
175+
has created a relationship, but which have not reciprocated
176+
"""
135177
from_relationships = self.get_relationships(status)
136178
to_relationships = self.get_related_to(status)
137179
return from_relationships.exclude(pk__in=to_relationships.values_list('pk'))
138180

139-
def exists(self, user, status=None):
140-
query = {
141-
'to_users__from_user': self.instance,
142-
'to_users__to_user': user,
143-
'to_users__site__pk': settings.SITE_ID
144-
}
145-
if status:
146-
query['to_users__status'] = status
147-
148-
return User.objects.filter(**query).count() != 0
149-
150-
def symmetrical_exists(self, user, status=None):
151-
query = {
152-
'to_users__from_user': self.instance,
153-
'to_users__to_user': user,
154-
'to_users__site__pk': settings.SITE_ID,
155-
'from_users__to_user': self.instance,
156-
'from_users__from_user': user,
157-
'from_users__site__pk': settings.SITE_ID
158-
}
159-
181+
def exists(self, user, status=None, symmetrical=False):
182+
"""
183+
Returns boolean whether or not a relationship exists between the given
184+
users. An optional :class:`RelationshipStatus` instance can be specified.
185+
"""
186+
query = dict(
187+
to_users__from_user=self.instance,
188+
to_users__to_user=user,
189+
to_users__site__pk=settings.SITE_ID,
190+
)
191+
160192
if status:
161-
query.update({
162-
'to_users__status': status,
163-
'from_users__status': status
164-
})
193+
query.update(to_users__status=status)
194+
195+
if symmetrical:
196+
query.update(
197+
from_users__to_user=self.instance,
198+
from_users__from_user=user,
199+
from_users__site__pk=settings.SITE_ID
200+
)
201+
202+
if status:
203+
query.update(from_users__status=status)
165204

166-
return User.objects.filter(**query).count() != 0
205+
return User.objects.filter(**query).exists()
167206

168207
# some defaults
169208
def following(self):
@@ -179,7 +218,7 @@ def blockers(self):
179218
return self.get_related_to(RelationshipStatus.objects.blocking())
180219

181220
def friends(self):
182-
return self.get_symmetrical(RelationshipStatus.objects.following())
221+
return self.get_relationships(RelationshipStatus.objects.following(), True)
183222

184223

185224
if django.VERSION < (1, 2):

0 commit comments

Comments
 (0)