Django - select model linked to itself - python

Jello!
I'm working with django right now and I have a problem which I suspect has a simple solution, but I've had a lot of difficulty trying to find it (most of the relevant keywords tend to point google to the wrong places).
I'm looking to filter a query based on the criteria that: A model has a field that points to itself.
I'll give an example:
class Person(models.Model):
name = models.CharField(max_length=20)
parent = models.ForeignKey('app.Person', null=True)
gramps = Person.objects.create(name='Tod', parent=None)
pops = Person.objects.create(name='Hank', parent=gramps)
sonny_boy = Person.objects.create(name='Tim', parent=pops)
temporal_paradox_dude = Person.objects.create(name='Emmett')
temporal_paradox_dude.parent = temporal_paradox_dude
temporal_paradox_dude.save()
temporal_paradox_dude_2 = Person.objects.create(name='Arnold')
temporal_paradox_dude_2.parent = temporal_paradox_dude_2
temporal_paradox_dude_2.save()
So the question is, in this case, how can I query the Person table for only people who are temporally paradoxical?
>>> Person.objects.filter(parent=SOME_WAY_OF_DECLARING_ITSELF)
[ 'Emmett', 'Arnold' ]
What do I need to replace SOME_WAY_OF_DECLARING_ITSELF with in order to get models that link to themselves?
Thanks!

I think you looking for something like this;
from django.db.models import F
Person.objects.filter(parent_id=F('id'))

You could do a simple query and then filter by iterating through that query:
results = [x for x in Person.objects.all() if x.parent == x]

Related

How can I paginate EmbeddedDocumentListField objects in Mongoengine?

Here are my classes. What is a good way to query the User for the embedded Review objects and paginate it somehow?
class Review(EmbeddedDocument):
review_body = StringField(required=True)
review_stars = FloatField(required=True, default=0)
reviewer = LazyReferenceField('User')
review_date = DateTimeField()
class User(Document):
userreviews = EmbeddedDocumentListField(Review)
I'm sure I can get the total easily with .count() but I'm not sure how to skip and query for only a portion of the objects.
The answer, it seems, lies in the way I was querying the database. I was doing it incorrectly for what I was trying to accomplish.
What wasn't working:
userprofile: user.User = user.User.objects(
username=request.form["username"]).get()
all_reviews = userprofile.userreviews # work with objects here
What should work:
Using .filter() and .slice() I can get the embedded Review objects like so:
reviews = user.User.objects.filter(username=request.form["username"]).fields(
slice__userreviews=[0, 2])
for r in reviews:
print(r.userreviews)
This will return 2 review objects starting at the index of 0. Then I just need to use .count() to get the total amount and I should have the 3 elements I need for pagination.

How to retrieve a distribution of values for a models field using Django?

I have a model like this:
class Question(models.Model):
#something
class Answer(models.Model):
question = models.ForeignKey(Question)
points_achieved = models.PositiveSmallIntegerField()
Now I want to query for the distribution of points_achieved: For each question I want to know how many scored 0 points, 1 points, etc.
In python I would do this as follows:
dists = []
for q in Question.objects.all():
dist = defaultdict(int)
for answer in q.answer_set.all():
dist[answer.points_achieved]+=1
dists.append(dist)
How can I accomplish the same using Django's querying methods?
Try this
from django.db.models import Count
Answer.objects.all().values('question', 'points_achieved').annotate(total=Count('points_achieved')).order_by('total')
Source: Django Aggregation
After some more wild-guessing and following this tutorial, I managed to come up with this solution:
Answer.objects.values('question','points_achieved')
.annotate(Count('points_achieved'))

Django Filter deduce ManyToMany

Simple models with many to many relations on the Tag field.
class Tag(models.Model):
description = models.TextField()
class Species(models.Model):
name = models.CharField(max_length=256)
tags = models.ManyToManyField(Tag)
Now Im trying this, and as I understand, it should return a list that matches every tag_description in the tags list:
tag_list = request.GET.get('q').split(',')
species = Species.objects.filter(reduce(and_, [Q(tags__description=c) for c in tag_list]))
But its returning an empty list. It should be returning some objects.
It works when I give it only one tag
any idea why this is happening?
Im using it as was shown in this answer:
https://stackoverflow.com/a/8636836/228660
As you can actually see in the comments of that question, it doesn't actually work ;)
The problem is that you will be using the same join (which means the same object) for all filters. Unless all items in tag_list are identical this will never work. The problem lies within the Q objects instead of full filtered queries.
tag_list = request.GET.get('q').split(',')
# Generate a query with all species
all_species = Species.objects.all()
# Generate a list with the separately filtered species
filtered_species = [all_species.filter(tags__description=c) for c in tag_list]
# Join the filtered species together using the same method :)
species = reduce(and_, filtered_species, all_species)
I think another way of doing this would be:
tag_list = request.GET.get('q').split(',')
species = Species.objects.all().distinct()
for tag in tag_list:
species = species.filter(tags__description=tag)
else:
species = Species.objects.none()

Getting only the models related to a Django queryset

I don't have much experience with Django (I'm using 1.3) so I have the feeling on the back of my head that this is a dumb question... But anyway:
I have models like this:
class User(models.Model):
name = models.CharField()
class Product(models.Model):
name = models.CharField()
public = models.BooleanField()
class Order(models.Model):
user = models.ForeignKey(User)
product = models.ManyToManyField(Product, through='OrderProduct')
class OrderProduct(models.Model):
product = models.ForeignKey(Product)
order = models.ForeignKey(Order)
expiration = models.DateField()
And let's say I do some query like this
Product.objects.filter(order__status='completed', order__user____id=2)
So I'd get all the products that User2 bought (let's say it's just Product1). Cool. But now I want the expiration for that product, but if I call Product1.orderproduct_set.all() I'm gonna get every entry of OrderProduct with Product1, but I just want the one returned from my queryset.
I know I can just run a different query on OrderProducts, but that would be another hit on the database just to bring back data the query I ran before can already get. .query on it gives me:
SELECT "shop_product"."id", "shop_product"."name"
FROM "shop_product"
INNER JOIN "shop_orderproducts" ON ("shop_product"."id" = "shop_orderproducts"."product_id")
INNER JOIN "shop_order" ON ("shop_orderproducts"."order_id" = "shop_order"."id")
WHERE ("shop_order"."user_id" = 2 AND "shop_order"."status" = completed )
ORDER BY "shop_product"."ordering" ASC
If I could SELECT * instead of specific fields I'd have all the data that I need in one query. Is there anyway to build that query and get only the data related to it?
EDIT
I feel I need to clarify some points, I'm sorry I haven't been clearer:
I'm not querying against OrderProduct because some products are public and don't have to be bought but I still have to list them, and they'd not be returned by a query against OrderProduct
The result I'm expecting is a list of products, along with their Order data (in case they have it). In JSON, it'd look somewhat like this
[{id: 1, order: 1, expiration: 2013-03-03, public: false},
{id: 1, order: , expiration: , public: true
Thanks
I'm gonna get every entry of OrderProduct with Product1, but I just
want the one returned from my queryset.
You just want which "one"? Your query is filtering on the Product model, so all Users, Orders, and OrderProducts associated with each of the Products in the returned queryset will be accessible.
If you want one specific OrderProduct, then you should be filtering as op = OrderProduct.objects.filter(xxxxx) and then accessing the models up the chain like so:
op.product, op.order, etc.
I would have suggested the method prefetch_related, but this isn't available in Django 1.3.
Dan Hoerst is right about selecting from OrderProduct, but that still hits the database more than necessary. We can stop that by using the select_related method.
>>> from django.db import connection
>>> len(connection.queries)
0
>>> first_result = OrderProduct.objects.select_related("order__user", "product")
... .filter( order__status="completed",
... order__user__pk=2 )[0]
>>> len(connection.queries)
1
>>> name = first_result.order.user.name
>>> len(connection.queries)
1
>>> product_name = first_result.product.name
>>> len(connection.queries)
1

Django help - how to get data from foreign keys

Given the following model setup (stripped down):
class Object(models.Model):
name = models.CharField(max_length=255)
class ObjectVersion(models.Model):
Cabinet = models.ForeignKey(Object)
Say I had a bunch of ObjectVersion entries that I'd filtered called "filteredObjects". How would I get the names of those objects into a vector?
You can use either values_list or values. The docs are available on the Django QuerySet API reference here.
>>> ObjectVersion.objects.filter(...).values('Cabinet__name')
[{'Cabinet__name':'foo'}, {'Cabinet__name':'foo2'}, ...]
or
>>> ObjectVersion.objects.filter(...).values_list('Cabinet__name')
[('foo',), ('foo2',), ...]
so you are saying that you have a list called filteredObjects?
objNames = [fo.name for fo in filteredObjects]
result = ObjectVersion.objects.filter(your filters here).values_list('Cabinet__name', flat=True)
Output:
result = ['ver_1', 'ver_2'..]

Categories

Resources