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.
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}
Related
I want to implement in my application something similar to instagram's local notifications.
The main problem is that local notifications can be different types. For example:
1) Simple one: "user started following you" (this is pretty straightforward)
2) More complicated: "user and +7 other liked your photo X"
The first step of solution is to GROUP all notifications by targeted_user, event_type and user_who_triggered_event. For the first case it's okay as we will have all information. For the second case we will lack some information as Count of similar notifications. Also what if I need some additional information about those +7 user's who also liked photo X?
What I've tried:
I've tried to use GROUP BY which can work for the second case but is not okay for the first. Also I tried to do 2 separate querysets which has all needed data for each type of notification. But then I'll have a problem that I cannot combine them and also cannot use pagination. Also if I'll return 2 querysets it will be hard for front-end to sort them by datetime
The first queryset:
ReceivedNotification.objects.filter(user=user)
The second one:
ReceivedNotification.objects.filter(user=user, notification__event=Notification.LIKED_PHOTO).values_list('receiver', 'notification__event')
class Notification(TimeStampedModel):
OPEN_PROFILE = 'open_profile'
OPEN_PHOTO = 'open_photo'
ACTION_CHOICES = (
(OPEN_PROFILE, _('Open profile')),
(OPEN_PHOTO, _('Open photo')),
)
LIKED_PHOTO = 'liked_photo'
NEW_FOLLOWER = 'new_follower'
EVENT_CHOICES = (
(LIKED_PHOTO, _('Liked photo')),
(NEW_FOLLOWER, _('New follower'))
)
action = models.CharField(
max_length=255,
choices=ACTION_CHOICES,
)
event = models.CharField(
max_length=255,
choices=EVENT_CHOICES,
)
title = models.CharField(
max_length=255,
)
body = models.TextField()
class Meta:
db_table = 'notifications'
For this example I have 2 notifications in data base.
Also I have ReceivedNotification model with FK to user and FK to notification and also data field(JSONField) to store actual information
which particular user will get.
Expected result is to get all local notifications for particular user is a single query.
Some notifications should have only basic info and other should have Counter of similar notifications if there are more than 3 similar and also list of Id's of that users.
We are on Django 1.5 (for now, until the boss can be convinced otherwise...)
The app has multiple objects that reference each other as foreign keys:
class Result(models.Model):
quiz = models.ForeignKey(Quiz)
user = models.ForeignKey(User)
class Quiz(models.Model):
quiz_type = models.CharField(max_length=1, choices=TYPE_CHOICES, default=TYPE_POST)
name = models.CharField(max_length=200)
lesson = models.ForeignKey(Lesson, blank=True, null=True, db_index=True)
class Lesson(models.Model):
title = models.CharField(max_length=200)
unit = models.ForeignKey(Unit)
class LessonStatus(models.Model):
user = models.ForeignKey(User)
lesson = models.ForeignKey(Lesson)
attempts_remaining = models.IntegerField(default=1)
passed = models.PositiveIntegerField(default=0)
For reporting, I need to get all Results for a specified user (or users), apply some filters based on user input, and then display a table with data that includes fields from User, Quiz, Lesson, and Unit. (It also checks LessonStatus for some display options.)
Right now, most of the foreign key queries are being done in a loop in the template, which is.. bad. I tried using select_related - my query log shows that it is successfully doing the table joins, but doesn't actually assign the fields to anything, so it seems that when I reference a related field, it's still causing a new query.
I have found similar questions, where the answers suggested using annotate, but that's not working for me.
I have tried:
r = Result.objects.filter(user__in=students).filter(~Q(quiz__quiz_type='3'))
r.annotate(qt=F('quiz__quiz_type'))
but that gets me : 'F' object has no attribute 'lookup'. This is the same whether or not I do a select_related('quiz'). What am I doing wrong?
Adding code from view:
r = Result.objects.filter(user__in=students).filter(~Q(quiz__quiz_type='3'))
r.select_related('quiz').select_related('user').select_related('lesson').select_related('unit')
if test_type != 'all':
r = r.filter(Q(quiz__quiz_type=test_type))
quiz__quiz_type='3')
if grade != 'any':
r = r.filter(Q(quiz__lesson__unit__grades=grade))
#more filters
for test in r:
if test.quiz.quiz_type == "1":
tu = test.user_id
try:
status = LessonStatus.objects.get(user=tu, lesson=test.quiz.lesson.id)
My expectation was that when I do the select_related, it shouldn't need to do additional queries for the related objects. However, I'm seeing queries on Quiz in that forloop, so I'm obviously doing something wrong.
Template:
(in a loop of for result in results)
{{result.user.first_name|title}} {{result.user.last_name|title}}
{{ result.quiz.lesson.title }}
{{ result.quiz.lesson.unit.title }}
{{ result.quiz.get_quiz_type_display }}
Query log is showing queries for each lesson and unit, so again, I'm doing something horribly wrong..
You need to follow the relationships on the select_related call itself; lesson and unit are not fields on Result, so will be ignored. It should be:
Result.objects.filter(...).select_related("quiz__lesson__unit", "user")
I am implementing a web interface for email lists. When a list administrator logs in, the site will visually display which lists they are an owner of and corresponding information about the lists. For this I have decided to have two tables:
1) An owner table which contains entries for information about list administrators. Each of these entries contains a 'ManyToManyField' which holds the information about which lists the owner in any given entry is an administrator for.
2) A list table which contains entries with information about each email list. Each entry contains the name of the list a 'ManyToManyField' holding information about which owners are administrators the list.
Here is the code in models.py:
from django.db import models
class ListEntry(models.Model):
name = models.CharField(max_length=64)
owners = models.ManyToManyField('OwnerEntry')
date = models.DateTimeField('date created')
class Meta:
ordering = ('name',)
class OwnerEntry(models.Model):
name = models.CharField(max_length=32)
lists = models.ManyToManyField('ListEntry')
class Meta:
ordering = ('name',)
I have already set up a simple local database to create a basic working website with. I have populated it with test entries using this code:
from list_app.models import *
from datetime import *
le1 = ListEntry(
name = "Physics 211 email list",
date = datetime.now(),
)
le1.save()
le2 = ListEntry(
name = "Physics 265 email list",
date = datetime(2014,1,1),
)
le2.save()
oe1 = OwnerEntry(
name = 'wasingej',
)
oe1.save()
oe1.lists.add(le1,le2)
le1.owners.add(oe1)
le2.owners.add(oe1)
oe2 = OwnerEntry(
name = 'doej',
)
oe2.save()
oe2.lists.add(le1)
le1.owners.add(oe2)
Here is where my error occurs: When the user has logged in via CAS, I have them redirected to this page in views.py:
def login_success(request):
u = OwnerEntry(name=request.user)
print(u.name)
print(u.lists)
return HttpResponse("login success!")
At the line 'print(u.lists)', I get the error "" needs to have a value for field "ownerentry" before this many-to-many relationship can be used.
What am I doing wrong here?
Your model structure is broken, for a start. You don't need ManyToManyFields on both sides of the relationship, only one - Django will provide the accessor for the reverse relationship.
Your issue is happening because you are not querying an existing instance from the database, you are instantiating an unsaved one. To query, you use model.objects.get():
u = OwnerEntry.objects.get(name=request.user.username)
You need to provide the actual class to the ManyToManyField constructor, not a string.
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/
I have two models, Recieved_order and order,
class Order(SmartModel):
restaurant = models.ForeignKey(Restaurant,null=True,blank=True,default = None,help_text="The restaurant the customer order from")
#contact info
email = models.EmailField(max_length=50,help_text="Needed as alternative")
mobile = PhoneNumberField(max_length=20,default='+25078######')
class Recieved_Order(SmartModel):
item = models.ForeignKey(Item)
date_added = models.DateTimeField(auto_now=True,auto_now_add=True)
quantity = models.IntegerField(default=0)
price = models.DecimalField(max_digits=9,decimal_places=2)
order = models.ForeignKey(Order)
i want a restaurant manager(user), to be able to receive orders(Recieved_order) made to his specific restaurants when logged in, to achieve this, i have the following in views.py
class Recieved_OrderCRUDL(SmartCRUDL):
model = Recieved_Order
actions = ('create','read','update','delete','list')
permissions = True
class List(SmartListView):
fields = ('order_email','order_mobile','order_billing_city','item.name','item.price','quantity','order_id','order_restaurant')
search_fields = ('date_added',)
def get_queryset(self,*args,**kwargs):
queryset = super(Recieved_OrderCRUDL.List, self).get_queryset(*args,**kwargs)
if self.request.user.is_superuser:
return queryset
return queryset.filter(order=self.request.user)
with the above i am testing on two different restaurants, the restaurant and its not working out as it should. its returning the wrong orders for a given restaurant.
What am i not doing right with get_queryset().
There's something confusing going on here:
return queryset.filter(order=self.request.user)
You're telling it to build a query that filters Order objects against User objects.
Is there something missing in your sample code that ties orders back to users such that a proper join can be constructed?
If you want to have a user (what you refer to as a manager) only able to view their own orders, you need to change things... Restaurant will need to have a field that points to a User (let's call it user and assume it's a ForeignKey) Then you can do something like
if self.request.user.is_superuser:
return queryset
return queryset.filter(order__restaurant__user=self.request.user)
As pointed out by #Joe Holloway, you should not be trying to filter on the order field with a user object...
The other odd thing I wanted to point out is
fields = ('order_email','order_mobile','order_billing_city','item.name','item.price','quantity','order_id','order_restaurant')
You appear to be using a mixture of ways to attempt to access things...
You should be using __ (that's 2 underscores) to access relations, not _ or .
I need to get a list of users who have been referenced as a ForeignKey in two other models. I'm still a little unclear on queries when they reach this complexity.
Models:
class Page(models.Model):
user = models.ForeignKey(User)
class EmailSent(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=200)
In English, what I want to get is: 10 active users who have 0 pages and have never had an email with the name check_in sent to them.
Here's where I am:
users = User.objects.filter(is_active=1).annotate(page_count=Count('pages')).filter(page_count=0)[10]
but not sure how to do what is essentially:
email_sent = EmailSent.objects.filter(user=user, name='check_in')
Any ideas?
One possible way to get what you want is:
users = User.objects.filter(is_active=1).annotate(page_count=Count('pages')).filter(page_count=0)
EmailSent.objects.filter(user__in=users, name='check_in')[10]
Another way is,
users = User.objects.filter(is_active=1).annotate(page_count=Count('pages')).filter(page_count=0)
users.emailsent_set.all()[10]
Try the following:
users = User.objects.filter(is_active=1)\
.exclude(emailsent__name='check_in')\
.extra(select={'page_count': "select count(*) from YOURAPP_page where user_id = auth_user.id"}, where=['page_count 0'])[:10]