How passing string on filter keyword to Django Objects Model? - django

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

Related

Call method on Django fields

class Colour(models):
...
def colour_preview(self):
return format_html(...)
class ColourTheme(models):
colour1 = models.ForeignKey(Colour)
colour2 = models.ForeignKey(Colour)
colour3 = models.ForeignKey(Colour)
...
def preview(self):
for field in self._meta.get_fields(include_parents=False):
if (field.related_model == Colour):
field.colour_preview()
I have a ColourTheme model with multiple Colour foreign keys, and I want to call a function on each of the Colour objects referred to by those fields. The last line of code above fails. I would like to call colour_preview on all Colour fields without hardcoding them (self.colour1.colour_preview() works but not ideal).
How might I achieve this?
You cannot refer to the field in order to access related object method.
Try something like this (I haven't tested it):
class ColourTheme(models):
colour1 = models.ForeignKey(Colour)
colour2 = models.ForeignKey(Colour)
colour3 = models.ForeignKey(Colour)
...
def preview(self):
for field in self._meta.get_fields(include_parents=False):
if (field.related_model == Colour):
field_obj = field.value_from_obj(self) # To get obj reference
field_obj.colour_preview()

How to execute a function when a variable's value is changed?

In Odoo 10, I want to change the value of a variable when the forecasted quantity of a product is changed. I tried using the #api.onchange decorator, but it doesn't work. The forecasted quantity change, but the variable keeps the same value. I have this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.was_changed = True
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))
In this code, if the forecasted quantity of a product would change, the variable was_changed should be set to True, but nothing happens.
After that, I tried to overwrite the write method for my custom class, like this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default=False)
#api.multi
def write(self, values):
if values['virtual_available']:
values['was_changed'] = True
# THE FOLLOWING LINES WERE IN THE ORIGINAL WRITE METHOD
res = super(MyProduct, self).write(values)
if 'standard_price' in values:
self._set_standard_price(values['standard_price'])
return res
But still, I have the same result. I can't seem to get that flag to change. So, any ideas?
Try this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.write({'was_changed': True})
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))

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

Django: Simplifying long 'join's?

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"
)