exclude a query result in another query - django

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

Related

how to select fields in related tables quickly in django models

I'm trying to get all values in current table, and also get some fields in related tables.
class school(models.Model):
school_name = models.CharField(max_length=256)
school_type = models.CharField(max_length=128)
school_address = models.CharField(max_length=256)
class hometown(models.Model):
hometown_name = models.CharField(max_length=32)
class person(models.Model):
person_name = models.CharField(max_length=128)
person_id = models.CharField(max_length=128)
person_school = models.ForeignKey(school, on_delete=models.CASCADE)
person_ht = models.ForeignKey(hometown, on_delete=models.CASCADE)
how to quick select all info i needed into a dict for rendering.
there will be many records in person, i got school_id input, and want to get all person in this school, and also want these person's hometown_name shown.
i tried like this, can get the info i wanted. And any other quick way to do it?
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name'))
person_name, person_id, school_name, school_address, hometown_name
if the person have many fields, it will be a hard work for list all values.
what i mean, is there any queryset can join related tables' fields together, which no need to list fields in values.
Maybe like this:
m=person.objects.filter(person_school_id=1).XXXX.values()
it can show all values in school, and all values in hometown together with person's values in m, and i can
for x in m:
print(x.school_name, x.hometown_name, x.person_name)
You add a prefetch_related query on top of your queryset.
prefetch_data = Prefetch('person_set, hometown_set, school_set', queryset=m)
Where prefetch_data will prepare your DB to fetch related tables and m is your original filtered query (so add this below your Person.objects.filter(... )
Then you do the actual query to the DB:
query = query.prefetch_related(prefetch_data)
Where query will be the actual resulting query with a list of Person objects (so add that line below the prefetch_data one).
Example:
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name'))
prefetch_data = Prefetch('person_set, hometown_set, school_set', queryset=m)
query = query.prefetch_related(prefetch_data)
In that example I've broken down the queries into more manageable pieces, but you can do the whole thing in one big line too (less manageable to read though):
m=person.objects.filter(person_school_id=1)
.values('id', 'person_name', 'person_id',
school_name=F('person_school__school_name'),
school_address=F('person_school__school_address'),
hometown_name=F('person_ht__hometown_name')).prefetch_related('person, hometown, school')

related field nested lookup error

I have the following models:
class Profile(models.Model):
user = models.ForeignKey(User)# User can have more than one profile
class Order(models.Model):
ship_to = models.ForeignKey(Profile)
class Shipping(models.Model):
order = models.ForeignKey(Order)# one order can have more than one shipping
shipping_company = models.ForeignKey(Shipping_company)
class Shipping_company(models.Model):
name = ...
So now i have the following structure:
User > Receiver > Order > Shipping > Shipping_company
The question is: How can i get all User models, who ordered with specific Shipping company?
If i make a query like this
User.objects.filter(receiver__order__shipping__shipping_company__pk=1)
i get
FieldError: Relation fields do not support nested lookups
if i make something like this
sh_comp = items.objects.get(pk=1) # __unicode__ returns "FedEx"
User.objects.filter(receiver__order__shipping__shipping_company=sh_comp)
the result is
ValueError: Cannot query "FedEx": Must be "Receiver" instance.
This seemed to be a simple and trivial task, but i can't make it work.
One approach that can be taken is as following(I am only considering the four models you have presented in your question),
You have foreign key of Shipping company in Shipping model. So you can make use of model function here on Shipping_company model.
Take a look at this model function
class Shipping_company(models.Model):
fields...
def get_profiles(self):
shippings = Shipping.objects.filter(shipping_company=self)
users = list(set([x.order.ship_to for x in shippings]))
Explanation:
shippings = Shipping.objects.filter(shipping_company=self)
will return all the shippings for one Shipping company(FedEx in your case). Further loop through the shippings to get ship_to from order field.
PS: You can take it as reference and design your own solution.
Walkthrough:
Lets say there is shipping company 'FedEx'. So we do,
fedex = Shipping_company.objects.get(name='FedEx')
Now, when you call get_profiles on fedex, like
fedex.get_profiles()
what will happen is this.
fedex instance refers to self in get_profiles() function now.
Using self(fedex), we filter out shippings by fedex.
Then we loop through those shippings to get order per shipping and each of that order has a ship_to(profile) foreign key.
I guess, you are getting confused because of the return statement.
In elaborate fashion the whole function will look something like this
def get_profiles(self):
users = list()
shippings = Shipping.objects.filter(shipping_company=self)
for shipping in shippings:
order = shipping.order
#Now you have an order per shipping, so you do
if not order.ship_to in users:
users.append(order.ship_to)
return users

I do not understand this error involving two objects with a many-to-many relation with one another

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/

Why is get get_queryset() not returning the right results?

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 .

Fetching ManyToMany objects from multiple objects through intermediate tables

Is there an easy way to fetch the ManyToMany objects from a query that returns more than one object? The way I am doing it now doesn't feel as sexy as I would like it to. Here is how I am doing it now in my view:
contacts = Contact.objects.all()
# Use Custom Manager Method to Fetch Each Contacts Phone Numbers
contacts = PhoneNumber.objects.inject(contacts)
My Models:
class PhoneNumber(models.Model):
number = models.CharField()
type = models.CharField()
# My Custom Manager
objects = PhoneNumberManager()
class Contact(models.Model):
name = models.CharField()
numbers = models.ManyToManyField(PhoneNumber, through='ContactPhoneNumbers')
class ContactPhoneNumbers(models.Model):
number = models.ForeignKey(PhoneNumber)
contact = models.ForeignKey(Contact)
ext = models.CharField()
My Custom Manager:
class PhoneNumberManager(models.Manager):
def inject(self, contacts):
contact_ids = ','.join([str(item.id) for item in contacts])
cursor = connection.cursor()
cursor.execute("""
SELECT l.contact_id, l.ext, p.number, p.type
FROM svcontact_contactphonenumbers l, svcontact_phonenumber p
WHERE p.id = l.number_id AND l.contact_id IN(%s)
""" % contact_ids)
result = {}
for row in cursor.fetchall():
id = str(row[0])
if not id in result:
result[id] = []
result[id].append({
'ext': row[1],
'number': row[2],
'type': row[3]
})
for contact in contacts:
id = str(contact.id)
if id in result:
contact.phonenumbers = result[id]
return contacts
There are a couple things you can do to find sexiness here :-)
Django does not have any OOTB way to inject the properties of the through table into your Contact instance. A M2M table with extra data is a SQL concept, so Django wouldn't try to fight the relations, nor guess what should happen in the event of namespace collision, etc... . In fact, I'd go so far as to say that you probably do not want to inject arbitrary model properties onto your Contact object... if you find yourself needing to do that, then it's probably a sign you should revise your model definition.
Instead, Django provides convenient ways to access the relation seamlessly, both in queries and for data retrieval, all the while preserving the integrity of the entities. In this case, you'll find that your Contact object offers a contactphonenumbers_set property that you can use to access the through data:
>>> c = Contact.objects.get(id=1)
>>> c.contactphonenumbers_set.all()
# Would produce a list of ContactPhoneNumbers objects for that contact
This means, in your case, to iterate of all contact phone numbers (for example) you would:
for contact in Contact.objects.all():
for phone in contact.contactphonenumbers_set.all():
print phone.number.number, phone.number.type, phone.ext
If you really, really, really want to do the injection for some reason, you'll see you can do that using the 3-line code sample immediately above: just change the print statements into assignment statements.
On a separate note, just for future reference, you could have written your inject function without SQL statements. In Django, the through table is itself a model, so you can query it directly:
def inject(self, contacts):
contact_phone_numbers = ContactPhoneNumbers.objects.\
filter(contact__in=contacts)
# And then do the result construction...
# - use contact_phone_number.number.phone to get the phone and ext
# - use contact_phone_number.contact to get the contact instance