How can I correct my ORM statement to show all friends not associated with a user in Django?
<p>In my Django application, I've got two models, one Users and one Friendships. There is a Many to Many relationship between the two, as Users can have many Friends, and Friends can have many other Friends that are Users.</p>

<p>How can I return all friends (first and last name) whom are NOT friends with the user with the first_name='Daniel'?</p>

<p>Models.py:</p>

<pre><code>class Friendships(models.Model):
    user = models.ForeignKey('Users', models.DO_NOTHING, related_name="usersfriend")
    friend = models.ForeignKey('Users', models.DO_NOTHING, related_name ="friendsfriend")
    created_at = models.DateTimeField(blank=True, null=True)
    updated_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'friendships'


class Users(models.Model):
    first_name = models.CharField(max_length=45, blank=True, null=True)
    last_name = models.CharField(max_length=45, blank=True, null=True)
    created_at = models.DateTimeField(blank=True, null=True)
    updated_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'users'
</code></pre>

<p>So far, here's what I've tried in my controller (views.py) -- please note, I understand controllers should be skinny but still learning so apologies. What I tried in the snippet below (after many failed attempts at a cleaner method) was to try and first grab friends of daniels (populating them into a list and then removing any duplicate ids), and then filter them out by their id.</p>

<pre><code># show first and last name of all friends who daniel is not friends with:

def index(req):

    friends_of_daniel = Friendships.objects.filter(user__first_name='Daniel')
    daniels_friends = []
    for friend_of_daniel in friends_of_daniel:
        daniels_friends.append(friend_of_daniel.friend.id)

    daniels_friends = list(set(daniels_friends))

    not_daniels_friends = Friendships.objects.exclude(id__in=daniels_friends)

    context = {
        'not_daniels_friends':not_daniels_friends,
    }

return render(req, "friendapp/index.html",context)
</code></pre>

<p>However, when I try the following in my views (templates) file, I still see individuals whom are friends of Daniels. Any idea what I'm doing wrong?</p>

<pre><code>&lt;ul&gt;
    {% for not_daniel_friend in not_daniels_friends %}
        &lt;li&gt;{{ not_daniel_friend.user.first_name }} {{ not_daniel_friend.user.last_name }}&lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</code></pre>

<p>Firstly as a general comment: a cleaner way of populating a list of ids is using the <a href="https://docs.djangoproject.com/es/1.10/ref/models/querysets/#django.db.models.query.QuerySet.values_list" rel="nofollow">.value_list() method from django</a> (part of the .values() method in previous versions of Django). It has a "flat" flag that creates the list you want.</p>

<p>So, instead of:</p>

<pre><code>friends_of_daniel = Friendships.objects.filter(user__first_name='Daniel')
    daniels_friends = []
    for friend_of_daniel in friends_of_daniel:
        daniels_friends.append(friend_of_daniel.friend.id)

    daniels_friends = list(set(daniels_friends))
</code></pre>

<p>You could do, in one line:</p>

<pre><code>daniels_friends = Friendships.objects \
       .filter(user__first_name='Daniel') \
       .distinct('friend') \
       .values_list('friend', flat=True)
</code></pre>

<p>distinct makes the same as your list() - set() cast (it makes sure that your list has no repeated elements) and values_list with flat=True can be customizable to any field in the related "user" table: .values_list('friend__id', flat=True) or .values_list('friend__first_name', flat=True) to get a list of first_names of Daniel's friends.</p>

<p>Coming back to your general question, you can do the whole query directly in one line using your related_names, as I am not really sure of what you want (an user instance, a Friendship instance or just a list of firsts and last names) I will give you many options:</p>

<ul>
<li><p>If you want a Friendship instance (what you are trying in your sample
code):</p>

<pre><code>friendships_not_friends_with_daniel = Friendships.objects\
        .exclude(friend__first_name="Daniel") 
</code></pre>

<p>This is equivalent to what @Rafael proposes in his answer:</p>

<blockquote>
  <p>daniels = Users.objects.filter(first_name="Daniel") # There may be
  more than one Daniel users =
  Friendships.objects.exclude(friend__in=daniels)</p>
</blockquote>

<p>Here I am embedding his first query in the exclude by referencing the
field in the related table with double underscore (which is an very
powerful standard in Django).</p></li>
<li><p>If you want an User instance:</p>

<pre><code>users_with_no_friendship_with_daniel = Users.objects\
        .exclude(usersfriend__friend__first_name="Daniel")
</code></pre>

<p>Here you are using the related name of your model to access from the
users table to the friendships table, and then check if the friend of this     user is called Daniel. This way of querying is a bit complex to understand but as soon as you get used to it becomes really powerful because it is very similar to the spoken language: you want all users, but excluding the ones that have a friendship, whose friend's first name is Daniel. Depending on how many friends an user hat or how many users are called Daniel, you might to add some distinct() methods or split the query in two.</p>

<p>As an advice, maybe you could improve the related name in your model, because it is what you would use if you have an user instance and want to get the related friendships: user_instance.friendships instead of user_instance.usersfriend and user_instance.friendsfriendships instead of user_instance.friendsfriend.... Do not know, it is always difficult to me to choose good related names...</p></li>
<li><p>If you want a list of tuples of users first and last names:</p>

<pre><code>names_of_users_with_no_friendship_with_daniel = Users.objects\
        .exclude(usersfriend__friend__first_name="Daniel")\
        .values_list('first_name', 'last_name')
</code></pre></li>
</ul>

<p>I am sorry if something is not clear, please ask and I try to explain better. (I am quite new in stackoverflow)</p>

python django orm many-to-many