I have a model Personne and each person may be linked to another person via a PersonneRelation model:
class Personne(BaseModel):
user = models.OneToOneField(User)
relations = models.ManyToManyField('self', through='PersonneRelation',
symmetrical=False,
related_name='personne_relations')
class PersonneRelation(BaseModel):
type_relation = models.IntegerField(
choices=[(a, b) for a, b in list(PersonneEnums.TAB_RELATIONS.items())],
default=PersonneEnums.RELATION_FRIEND)
src = models.ForeignKey('Personne', related_name='relation_src')
dst = models.ForeignKey('Personne', related_name='relation_dst')
is_reverse = models.BooleanField(default=False)
So, imagine one person A. He has a contact B. My client wants me to display all the contacts of B so that A might be able to send a message to those contacts. Pretty easy. The problem is that I've made a view that displays the "person" information and it's pretty simple, like /person/{id}. Thus if you change the {id} value, you can see another person information. What I need to check is:
if the person to display is a contact of A
if the person to display is a contact... of a contact of A
For now I'm doing an ugly query where I check all the contacts... of all the contacts of A.
How would you do an optimized query to check if the person to display is a contact... of a contact of A?
Returns True, if user can see other's information. user and other are instances of auth.User.
user.personne.relations.filter(
Q(user=other) | Q(relations__user=other)
).exists()
Related
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}
I have a person, which has a foreign key to User:
p = Personne.objects.get(user=self.request.user)
This person has "friends" through the model PersonneRelation where there's a src person and a dst person, so I'm retrieving all the person's friends like this:
friends = [a.dst.pk for a in PersonneRelation.objects.filter(src=p)]
I have a model Travel which embeds a description of a travel. I have also a model "activity" which is an activity the friend's current user have done (Activite). So here's the way I'm retrieving all the activities related to the current user:
context['activites'] = Activite.objects.filter(
Q(travel__personne__pk__in=friends) | Q(relation__src__pk__in=friends),
)
Everything works fine. I have also a model PersonneLiked where you precise if you liked an Activite. Thus this model has a foreign key to Activite.
class PersonneLiked(models.Model):
src = models.ForeignKey('Personne', related_name='liked_src')
dst = models.ForeignKey('Personne', related_name='liked_dst')
activite = models.ForeignKey('Activite', related_name='liked_activite')
# liked = thumb added *OR* removed :
liked = models.BooleanField(default=True)
What is the code I should do to retrieve all the PersonneLiked of context['activites']? It's like making an OUTER JOIN in SQL, but I dont know how I could do this with Django.
Since context['activities'] is a queryset of the appropriate Activite objects then you can do:
PersonneLiked.objects.filter(activite__in=context['activities'])
(Note that if this were a M2M relationship rather than a ForeignKey, this method would create duplicate entries in your final queryset.)
Here i want to do is that ,i want to list all the person who didn't blocked me.Here in the table Blocked there is two columns name
who and whose . In whose column i store the id of the person whom i blocked and in the who column i store my id. Now i want to do that, when the blocked person click on
view-person button in my web page he cannot see profile of the person one who blocked him.
when i did this query blocked_list = Blocked.objects.filter(whose = user_id). Now i got the list of the persons who blocked me. Now i want to exclude all this person from this query total_profiles = persons.objects.all().exclude(blocked_list). How can i do this.
models.py
class persons(models.Model):
full_name = models.CharField(max_length=200)
class blocked(models.Model):
who = models.ForeignKey(persons)
whose = models.IntegerField(null=True)
views.py
def blocked(request):
blocked_list = Blocked.objects.filter(whose = user_id)
total_profiles = persons.objects.all().exclude(blocked_list)
return render_to_response('profiles/view_all.html', {'total_profiles':total_profiles,'}, context_instance=RequestContext(request),)
please correct the question if it is not correct.
You can try this:
total_profiles = persons.objects.all().exclude(id__in = blocked_list.values_list('id', flat=True))
It's untested, but adapted from this answer.
Some notes:
if persons has the default manager, you can omit all().
whose does not have an index, so it will become slow when your dataset gets big. You can use a ForeignKey field instead of an IntegerField
the common convention is to capitalize class names and to write model names in singular i.e. Person instead of persons
I want to create an order form to buy multiple things in this sort of structure:
Business Data 1
---Product A
---Product B
Business Data 2
---Product A
That is, I want to sell products A,B, but before this is done I need additional aggregate data to be in the 'Business Data' object. That is:
Business 1: Joe's Plumbing, located at ... ... ...
---Product A, standard ad appearing in category 3, with text "awesome plumbing"
---Product B, cooler ad appearing in category 9, with text "cheap plumbing"
Business 2: Joe's Burgers, located at ... ... ...
---Product A, standard ad appearing in category 4, with text "zzz"
or, from a model level, more like:
class Business(models.Model):
name = models.CharField(max_length=255)
address = models.MagicAddressField()
class Ad(models.Model):
category = models.ForeignKey(Category)
text = models.CharField(max_length=255)
business = models.ForeignKey(Business)
Now, instead of reimplementing an entire shopping cart backend, I'm pretty sure I want to use Satchmo. However, i'm having trouble wrapping my head around this sort of thing.
Satchmo appears to have multiple options for Products, but they're all "flat". That is, while I could easily get Satchmo to allow the end user to buy Product A and Product B, the db shows no connection to Business 1, and things like the business name would have to be repeated in both product A and B.
I think I can probably get around this with my own views / templates, if only I can get the final "product instance" that satchmo is selling during an order to have a foreign key to the Business table i'll create myself. In other words, I want to make the Ad model a satchmo custom product model - I think...
But If I just change Ad to:
class Ad(Product):
objects = ProductManager()
category = models.ForeignKey(Category)
text = models.CharField(max_length=255)
business = models.ForeignKey(Business)
Isn't this the wrong semantics? Doesn't that mean that "this product type is associated with business x", not "when you buy this, the product's instance will be pointing to business x"?
I'm pretty confused here :-/
If I understood this right, I would make something like this.
Make a ManyToMany relationship between business and the products:
class Business(models.Model):
name = models.CharField(max_length=255)
address = models.MagicAddressField()
products = models.ManyToManyField(Product)
Then, on your custom-form and template/view, you can add for each business a fieldset with the Products/Ads for each business. The only complicatation I see by now, would be, that after filling up the form and sending it, you would also need customized "checkout-process" to save the information of which product got bought through which business... maybe this could be done through product-options(?) but any way it'll probably mean a lot of customization/working with signals ;-) But i think this is the right direction.
I am working with django and having a hard time grasping how to do complex queries
Here is my model
class TankJournal(models.Model):
user = models.ForeignKey(User)
tank = models.ForeignKey(TankProfile)
ts = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=50)
body = models.TextField()
class Meta:
ordering = ('-ts',)
get_latest_by = 'ts'
I need to pull the username given the tank object.
The user object is the one built into django.. thanks!
EDIT:
I have tried this
print User.objects.filter(tankjournal__tank__exact=id)
It seems to not pull out just the id.. and pull out everything in tankjournal and match it to the tank object
If you already have your tank object you should be able to do:
tank.user.username
To reduce the database queries you might want to consider the use of select_related(), e.g.
tanks = TankJournal.objects.all().select_related()
for tank in tanks:
username = tank.user.username
if you have a specific tank id then:
tank = TankJournal.objects.select_related().get(id=123456)
username = tank.user.username
I may be misunderstanding your question, but a request on User.objects.filter() will return a list of User objects, not User ids. What you've written looks technically correct.
Remember, though, that the model you have sets up a one-to-many between the TankProfile object and the TankJournal. In other words, a single TankProfile can be associated with more than one TankJournal, and therefore to more than one user. Given this, you're query is doing the right thing, returning more than one User.