is it possible to set associations between two objects, for example article and comment like this:
comment.setArticle(10) // 10 is the id of article
autogenerated setArtcicle methods takes as argument object Article of course but maybe there are some tricks to do this?
It is very important to me from performance point of view - i would like to avoid making SQL calls always when I want to set an association. In my case there will be plenty of such unnecessary queries.
You can use:
$comment->setArticle($em->getReference('Article', 10));
Related
I'm reviewing some code and I came across a line that does the following:
Person.find_by(name: "Tom").id
The above code gets the FIRST record with a name of "Tom", then builds a model, then gets the id of that model. Since we only want the id, the process of retreiving all data in the model and initializing the model is unneeded. What's the best way to optimize this using active record queries?
I'd like to avoid a raw sql solution. So far I have been able to come up with:
Person.where(name: "Tom").pluck(:id).first
This is faster in some situations since pluck doesn't build the actual model object and doesn't load all the data. However, pluck is going to build an array of records with name "Tom", whereas the original statement only ever returns a single object or nil - so this technique could potentially be worse depending on the where statement. I'd like to avoid the array creation and potential for having a very long list of ids returned from the server. I could add a limit(1) in the chain,
Person.where(name: "Tom").limit(1).pluck(:id).first
but is seems like I'm making this more complicated than it should be.
With Rails 6 you can use the new pick method:
Person.where(name: 'Tom').pick(:id)
This is a little verbose, but you can use select_value from the ActiveRecord connection like this:
Person.connection.select_value(Person.select(:id).where(name: 'Tom').limit(1))
This might work depending on what you're looking for.
Person.where(name: "Tom").minimum(:id)
Person.where(name: "Tom").maximum(:id)
These will sort by id value while the Person.where(name: "Tom").first.id will sort off of your default sort. Which could be id, created_at, or primary_key.
eitherway test and see if it works for you
I want to do something like
query.annotate(Count('foreign_model_relation', somefield_from_foreign_model=some_value))
That means, i want to count, how many objects from another queryset are pointing to this object. The difference between using something like filter(in=other_queryset) is, that i would like to combine this in one query, to avoid generating one query per object.
Simplified Models:
Group
Object
group (Group)
Vote
object (Object)
up (Boolean)
Now i want to query the up/down count of all Objects for one Group, with one or two queries, not with one/two queries per Object.
You can do this with two queries:
YourObject.objects.filter(vote__up=True, group=some_group).annotate(total_votes_up=Count('vote'))
YourObject.objects.filter(vote__up=False, group=some_group).annotate(total_votes_down=Count('vote'))
But I think that should exist some more elegante way to do this.
I am annotating my queryset in Django, using values from another table mapping as so.
lw_list = lw_list.annotate(count_mapping=Count('mapping'))
(lw objects have a one to many relationship with the mapping objects)
So now each object in my lw list has a count of related mapping objects.
My mapping objects have a boolean field 'pass_fail'
Is it possible to put a where clause on the mapping table, so that the aggreagte only counts mapping objects that have a "pass_fail" value set to true?
How do you do this?
I don't think this can be done using Django's ORM as of now -- here's a pretty active ticket about what you want, and here's a pretty hackish workaround suggested by someone in there. I'd say your best bet would be to use raw SQL for now.
I have the following model structure:
class Container(models.Model):
pass
class Generic(models.Model):
name = models.CharacterField(unique=True)
cont = models.ManyToManyField(Container, null=True)
# It is possible to have a Generic object not associated with any container,
# thats why null=True
class Specific1(Generic):
...
class Specific2(Generic):
...
...
class SpecificN(Generic):
...
Say, I need to retrieve all Specific-type models, that have a relationship with a particular Container.
The SQL for that is more or less trivial, but that is not the question. Unfortunately, I am not very experienced at working with ORMs (Django's ORM in particular), so I might be missing a pattern here.
When done in a brute-force manner, -
c = Container.objects.get(name='somename') # this gets me the container
items = c.generic_set.all()
# this gets me all Generic objects, that are related to the container
# Now what? I need to get to the actual Specific objects, so I need to somehow
# get the type of the underlying Specific object and get it
for item in items:
spec = getattr(item, item.get_my_specific_type())
this results in a ton of db hits (one for each Generic record, that relates to a Container), so this is obviously not the way to do it. Now, it could, perhaps, be done by getting the SpecificX objects directly:
s = Specific1.objects.filter(cont__name='somename')
# This gets me all Specific1 objects for the specified container
...
# do it for every Specific type
that way the db will be hit once for each Specific type (acceptable, I guess).
I know, that .select_related() doesn't work with m2m relationships, so it is not of much help here.
To reiterate, the end result has to be a collection of SpecificX objects (not Generic).
I think you've already outlined the two easy possibilities. Either you do a single filter query against Generic and then cast each item to its Specific subtype (results in n+1 queries, where n is the number of items returned), or you make a separate query against each Specific table (results in k queries, where k is the number of Specific types).
It's actually worth benchmarking to see which of these is faster in reality. The second seems better because it's (probably) fewer queries, but each one of those queries has to perform a join with the m2m intermediate table. In the former case you only do one join query, and then many simple ones. Some database backends perform better with lots of small queries than fewer, more complex ones.
If the second is actually significantly faster for your use case, and you're willing to do some extra work to clean up your code, it should be possible to write a custom manager method for the Generic model that "pre-fetches" all the subtype data from the relevant Specific tables for a given queryset, using only one query per subtype table; similar to how this snippet optimizes generic foreign keys with a bulk prefetch. This would give you the same queries as your second option, with the DRYer syntax of your first option.
Not a complete answer but you can avoid a great number of hits by doing this
items= list(items)
for item in items:
spec = getattr(item, item.get_my_specific_type())
instead of this :
for item in items:
spec = getattr(item, item.get_my_specific_type())
Indeed, by forcing a cast to a python list, you force the django orm to load all elements in your queryset. It then does this in one query.
I accidentally stubmled upon the following post, which pretty much answers your question :
http://lazypython.blogspot.com/2008/11/timeline-view-in-django.html
I have something like this:
Order order = new Order();
Item item = new Item();
order.Items.Add(item);
order.Save();
How can I do this with Subsonic? The method that refere to a related table is IQueryable.
You have three options:
Set the foreign key in Item to the id of your Order object and save both.
Create a partial class which has a method "AddItem", encapsulating this functionality
Modify the T4 templates to allow you to do this automatically; unfortunately this feature doesn't come out of the box yet.
The advantage with Subsonic is that it is flexible, however you occasionally have to fill some of the gaps yourself.
If you are programming something like a shopping cart you can abstract that out into it's own class that can handle marrying the objects together. I personally think it works better than modify the generated objects.