Django: Simplifying long 'join's? - django

I've got a few long queries (for checking capabilities) which look like this:
widgets = Widget.objects.filter(
Q(owner__memberships = current_user),
Q(owner__memberships__memberships__capabilities__name = "widget_list")
)
Is there any reasonable way of simplifying that query? Or do I just need to live with it?
The relevant models are:
class Widget(m.Model):
owner = m.ForeignKey(Group)
class Group(m.Model):
memberships = m.ManyToManyField(User, through=GroupMembership)
class GroupMembership(m.Model):
user = m.ForeignKey(User)
group = m.ForeignKey(Group)
capabilities = m.ManyToMany(Capability)
class Capability(m.Model):
name = m.CharField(...)

You don't need to wrap your parameters in Q() objects, you can use the key/value pairs directly:
widgets = Widget.objects.filter(
owner__memberships = current_user,
owner__memberships__memberships__capabilities__name = "widget_list"
)

Related

Django Model inheritance and access children based on category

I want to get the parent class values with each child values? How can I identify child objects to fetch?
I have the Django model structure like this.
class Category(models.Model):
name = models.CharField(max_length=80)
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
category = models.ForeignKey('Category')
class PizzaRestaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
class PastaRestaurant(Place):
extra = models.CharField(max_length=80)
When we do operation we may save the object like below. And it saved into the db as i expected. two entry in the Place table and each entry in each child object table.
a = Category()
a.name = "pasta"
b = Category()
b.name = "pizza"
a.save()
b.save()
x = PastaRestaurant()
x.address = "Pasta Address"
x.name = "Pastamonia"
x.extra = "some extra"
x.category = a
y = PizzaRestaurant()
y.address = "Pizza Address"
y.name = "Dominos"
y.serves_hot_dogs = 1
y.serves_pizza = 0
y.category = b
x.save()
y.save()
Now I need to access the like this
p = Place.objects.get(id=1)
How can I know, which objects/attributes belongs to the place objects?
So when I fetch the place with common attributes and should be able get the corresponding child objects values also.
Or any other model design work for my need?
If you want to access the child model's attributes you need to fetch it as that model, i e PizzaRestaurant or PastaRestaurant, otherwise you will only get a Place object.
If you need to get all Places regardless of subclass take a look at InheritanceManager from django-model-utils. Using this you can implement overloaded operations to perform subclass-specific actions.
django-polymorphic does this beautifully, improving the abilities to work with model inheritance like so:
from polymorphic.models import PolymorphicModel
class Place(PolymorphicModel):
...
class PizzaRestaurant(Place):
...
class PastaRestaurant(Place:
...
>>> some_place = Place.objects.create(name="Walmart")
>>> some_pizza_place = PizzaRestaurant.objects.create(name="Slice King", address="101 Main St., Bismarck, ND", category = Category.objects.first(),serves_pizza=True)
>>> some_pizza_place.instance_of(PizzaPlace)
True
>>> PizzaRestaurant.objects.all()
queryset<['Slice King',]>
>>> Place.objects.all()
queryset<['Walmart', 'Slice King',]>

Computed Property for Google Datastore

I am not sure exactly how achieve this.
I have a model defined as
class Post(ndb.Model):
author_key = ndb.KeyProperty(kind=Author)
content = ndb.StringProperty(indexed=False)
created = ndb.DateTimeProperty(auto_now_add=True)
title = ndb.StringProperty(indexed=True)
topics = ndb.StructuredProperty(Concept, repeated=True)
concise_topics = ndb.ComputedProperty(get_important_topics())
#classmethod
def get_important_topics(cls):
cls.concise_topics = filter(lambda x: x.occurrence > 2, cls.topics)
return cls.concise_topics
I like to set the value of concise_topics (Which is on the same type as topics) to a subset acheived via get_important_topics method. This should happen the moment the topics property has been set.
How do I define the "concise_topics" property in the Post class ?
With class method, you don't have access to the instance values. And also you shouldn't call the function, only pass it to the computed property, and let it call by itself.
class Post(ndb.Model):
author_key = ndb.KeyProperty(kind=Author)
content = ndb.StringProperty(indexed=False)
created = ndb.DateTimeProperty(auto_now_add=True)
title = ndb.StringProperty(indexed=True)
topics = ndb.StructuredProperty(Concept, repeated=True)
def get_important_topics(self):
return filter(lambda x: x.occurrence > 2, self.topics)
concise_topics = ndb.ComputedProperty(get_important_topics)
As far as I remember the computed property is set on each put call, so your topics should be already there by that time.

Django add new item to dict

thread_list = thread.objects.select_related().filter(thread_forum_id = current_obj.id).order_by('-thread_date')
for thread in thread_list:
count = post.objects.select_related().filter(post_thread_id = thread.id).count()
thread.post = count
How do that?
thread.post = count
^
class thread(models.Model):
mess = models.CharField(max_length=5000)
objects = thread_manager()
I want add new item to the list manualy.
Your question is not well-written, but I believe what you are looking for is annotation (docs here):
from django.db.models import Count
thread_list = thread.objects.select_related().filter(thread_forum_id=current_obj.id) \
.order_by('-thread_date').annotate(post_count=Count('post_thread_set'))
# I'm just guessing this name: 'post_thread_set'
The returned value is not a list of dicts, rather it is a queryset, which is an iterable of objects. You can then access post_count as an attribute:
thread_list[0].post_count
You way is good.
But there is a conflict:
thread_list = thread.objects.select_related().filter(thread_forum_id = current_obj.id).order_by('-thread_date')
for thread in thread_list:
count = post.objects.select_related().filter(post_thread_id = thread.id).count()
thread.post = count
Your class have name thread and your loop have name like class.
for thread in thread_list:
Just do that:
for threads in thread_list:
count = post.objects.select_related().filter(post_thread_id = threads.id).count()
threads.post = count
or something like this. Just change loop - i add 's' at the end of a word

How to get one query from two models?

I have two models:
class ModManager(models.Manager):
def myfilter(self, options = dict()):
if options.has_key('not_image'):
kwargs['image__isnull'] = False
return self.filter(**kwargs)
class Model_1(models.Model):
...
objects = MyManager()
class Model_2(models.Model):
something = models.ForeignKey(Model_1)
something_else = ...
...
How to get all data from Model_2 related to Model_1 in MyManager? I want to get one query. I have so far:
in Model_1:
def get_model_2(self):
self.model_2_objs = self.model_2_set.all()
But it generates many queries when I calling get_model_2 function.

How passing string on filter keyword to Django Objects Model?

How can i pass variables on a keyword object filter on a view?
I have:
my_object = MyModel.objects.filter(my_keyword =my_filter_values)
I want to grab my_keyword from a variable coming from a string, like this:
my_string = 'my_keyword'
my_object = MyModel.objects.filter(my_string=my_filter_values)
But this doesn't work because Django doesn't know my_string from MyModel.
Edit: I've found this SO question - I'll test and report back.
You can do something like this:
my_filter = {}
my_filter[my_keyword] = my_filter_value
my_object = MyModel.objects.filter(**my_filter)
As an example, your variables might be:
my_keyword = 'price__gte'
my_filter_value = 10
Which would result in getting all objects with a price >= 10. And if you want to query on more than one field, you can just add another line below my_filter[my_keyword]:
my_filter[my_keyword] = my_filter_value
my_filter[my_other_keyword] = my_other_filter_value