RC-
RC-

Reputation: 163

Django ORM verification of a row in the database

In my site, the buyer search for a product and once he found it he can contact the seller by pressing on a contact button. If the conversation between the two concerning this product exists he should be redirected to the existing conversation, else, we create a new conversation. The conversation is hence defined by two users and a listing. When I try to implement the logic, I am not able to verify both conditions of the existance of the conversation, if the listing exists OR the users exists Django returns that the conversation exists. Here is my code:

def create_conversation(request, user_pk1, user_pk2, results_pk):
    user1 = get_object_or_404(get_user_model(), pk=user_pk1)
    user2 = get_object_or_404(get_user_model(), pk=user_pk2)
    results= get_object_or_404(Listing, pk=results_pk)
    existing_conversation = Conversation.objects.filter(users__in=[user1, user2]).filter(listing=results).values_list('id', flat=True)


    if existing_conversation.exists():

        return HttpResponseRedirect(reverse('conversation:conversation_update', kwargs={'pk':existing_conversation[0]}))
    else:
        conv=Conversation()
        conv.save()
        conv.listing = results
        conv.save()
        conv.users.add(*[user1,user2])
        return HttpResponseRedirect(reverse('conversation:conversation_update', kwargs={'pk': conv.pk}))

Here is the model of the conversation:

class Conversation(models.Model):
    """
    Model to contain different messages between one or more users.

    :users: Users participating in this conversation.
    :archived_by: List of participants, who archived this conversation.
    :notified: List of participants, who have received an email notification.
    :unread_by: List of participants, who haven't read this conversation.]\['
    listing: the listing the conversation is about.
    read_by_all: Date all participants have marked this conversation as read.

    """
    users = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        verbose_name=_('Users'),
        related_name='conversations',
    )
# review the listing before going online, because it is necessary to have a conversation listing
    listing = models.ForeignKey (
        Listing,
        verbose_name=_('Listing'),
        related_name='listing',
        default= 1,
    )

and the model of the listing:

class Listing(models.Model):

seller = models.ForeignKey(Profile, related_name='seller_listing', verbose_name='sellr', limit_choices_to={'is_seller': True})
    location_Country = models.CharField(max_length=45, verbose_name=_('from_Country'))
    location_State = models.CharField(max_length=45, verbose_name=_('from_State'), null=True, blank=True)
    location_City = models.CharField(max_length=45, verbose_name=_('from_City'))

I also tried an approach of divinding it into two conditions: a = conversation.objects.filter(users) and b= conversation.objects.filter(listing), then use if a and b then the conversation exists but got the same issue.

and existing_conversation = Conversation.objects.filter(Q(users__in=[user1, user2]) & Q(listing=results)).values_list('id', flat=True) but got the same issue. Thank you in advance for your help.

Upvotes: 1

Views: 67

Answers (1)

Lemayzeur
Lemayzeur

Reputation: 8525

You can use intersection() method of django, added since Django 1.11, operator to return the shared elements of two or more QuerySets or the bitwise operation AND used with the sign `& to get the same behavior.

So in your case, check whether there's an intersection between the two users with & or intersection()

existing_conversation = (user1.conversations.all() & user2.conversations.all()).filter(listing=results)

# or with django intersection

existing_conversation = (user1.conversations.all().intersection(user2.conversations.all())).filter(listing=results)

if existing_conversation.exists():
    return HttpResponseRedirect(reverse('conversation:conversation_update', 
       kwargs={'pk':existing_conversation.first().pk}))

 else:
    # rest of the code

BONUS, I see a typo in your code, you didn't send the pk as argument:

kwargs={'pk':existing_conversation[0]}

get the first instance with first() and get the pk

kwargs={'pk':existing_conversation.first().pk}

or

kwargs={'pk':existing_conversation[0].pk}

Upvotes: 1

Related Questions