Say I have the following many to many with jobs and users
Assignment:
columns:
job_id:
....
user_id:
....
relations:
user:
local: user_id
foreign: id
job:
local: job_id
foreign: id
is it possible to query Job and then join job.assignment so that the result returns all jobs and then also returns additional rows for each job.assignment?
Doctrine, when using the default Record hydration, returns objects and relations to other objects. In this mode, you can write a number of queries to get what you want, depending on what you are going to do with them. To get a list of Jobs, and grab all of their associated Assignments and Users, use:
$jobs = Doctrine_Query::create()
->from('Job j')
->leftJoin('j.Assignments a')
->innerJoin('a.user u')
->execute();
foreach($jobs as $job) {
foreach($job->Assignments as $assignment) {
$user = $assignment->user;
// do something with $job and $user here
}
}
In this case, you'll need to add the relation from Job to Assignment. If you want to do the reverse, get a list of users and join to their jobs, use:
$users = Doctrine_Query::create()
->from('User u')
->leftJoin('u.Assignments a')
->innerJoin('a.job j')
->execute();
foreach($users as $user) {
foreach($user->Assignments as $assignment) {
$job = $assignment->job;
// do something with $job and $user here
}
}
In this case, you'll need the relation from User to Assignment.
You can even start with Assignments, if that is what you're looking for:
$assignments = Doctrine_Query::create()
->from('Assignment a')
->innerJoin('a.user u')
->innerJoin('a.job j')
->execute();
foreach($assignments as $assignment) {
$user = $assignment->user;
$job = $assignment->job;
// do something with $job and $user here
}
The first query will give you all jobs, even ones without assignments. The second, all users, also ones without assignments. The third, assignments, which will have users and jobs, if they are required.
Related
Good day again SO. I was hoping you can help me with some of the logic.
Based on this SO Answer, I can filter the search with a list which works perfectly. However, I wish to get an EXACT id instead of at least one matches.
models:
class Condition:
condition_name = models.CharField(....)
class Jobs:
jobs = models.CharField(...)
class JobsConditions:
account = models.ForeignKey(Account...)
job_item = models.ForeignKey(Jobs...)
condition = models.ForeignKey(Condition...)
So if I try to search for Jobs with Conditions, I do the following:
cond_array = [1,2,4,5] # Append to array based on request.
condition_obj = Condition.objects.filter(id__in=cond_array)
Then compare condition_obj to JobsConditions model. How to use this so that I will only get only the jobs with exact condition? No more no less.
I think you're wanting something like this:
Filter JobsConditions by condition__id and get the associated job_item__jobs as a list:
jobs_list = (JobsConditions.objects
.filter(condition__id__in=cond_array)
.values_list('job_item__jobs', flat=True))
Filter Jobs by that jobs_list:
jobs = Jobs.objects.filter(jobs__in=jobs_list)
With the results of a Django raw query set using a query such as this:
for employee in employees:
staff = Staff.objects.raw('Long query... WHERE employee_id= %s', [employee.id])
I created a list, then created a dictionary.
final_list = []
for s in staff:
a = {
'first_name' : s.first_name,
}
final_list.append(dict(a))
print(final_list)
Resulting in this:
[{'first_name':u'John'}, {'first_name':u'Jill'}]
[]
[{'first_name':u'James'}, {'first_name':u'Susan'}]
[{'first_name':u'Bill'}]
How can I merge the results to get something like this:
[{'first_name':u'John'}, {'first_name':u'Jill'}, {'first_name':u'James'}, {'first_name':u'Susan'}, {'first_name':u'Bill'}]
You should append each final_list to another list final_lists:
You can concatenate these with list comprehension:
for employee in employees:
final_list = []
staff = Staff.objects.raw('Long query... WHERE employee_id= %s', [employee.id])
for s in staff:
a = {
'first_name' : s.first_name,
}
final_list.append(a)
final_lists.append(final_list)
result = [ li for l in final_lists for li in l ]
But the above is not a good idea. You can simply rewrite the query and fetch all the data in one pass:
staff = Staff.objects.raw(
'Long query... WHERE employee_id IN (%s)',
[[e.id for e in employees]]
)
result = [{'first_name': s.first_name} for s in staff]
Usually the performance scales linear with the amount of roundtrips to the database, and thus by fetching all data in a single query, you boost performance.
Actually using raw queries is usually not a good idea: it is less declarative, an ORM can sometimes slightly optimize queries, and if you later change the database dialect, the query automatically talks the other dialect.
Let us we have a Rails 4.2.x app and we have two tables posts and authors, and we want to use Arel to get the posts authored by an author with name == 'Karl'.
(In this case we could be happy with Active Record joins but this is just to keep the example simple.)
posts = Arel::Table.new :posts
authors = Arel::Table.new :authors
my_query = posts.project(Arel.star)
.join(authors)
.on(posts[:author_id].eq(authors[:id]))
.where(authors[:name].eq('Karl'))
> my_query.class
=> Arel::SelectManager
Now we could get back an array (of class Array) of posts by doing:
> Post.find_by_sql my_query
[master] Post Load (3.1ms) SELECT * FROM "posts" INNER JOIN "authors"
ON "posts"."author_id" = "authors"."id"
WHERE "authors"."name" = 'Karl'
=> [#<Post:0x005612815ebdf8
id: 7474,
...
]
So we do get an array of posts, not an active record relation:
> Post.find_by_sql(my_query).class
=> Array
Also injecting the manager into Post.where won't work
> Post.where my_query
=> #<Post::ActiveRecord_Relation:0x2b13cdc957bc>
> Post.where(my_query).first
ActiveRecord::StatementInvalid: PG::SyntaxError:
ERROR: subquery must return only one column
SELECT "posts".* FROM "posts"
WHERE ((SELECT * FROM "posts" INNER JOIN "authors" ON "posts"."author_id" = "authors"."id" WHERE "authors"."name" = 'Karel'))
ORDER BY "posts"."id" ASC LIMIT 1
I am thinking I must be missing something. In short: how do you get an active record relation from a select manager like my_query above (or another select manager accomplishing the same thing).
You can't get ActiveRecord::Relation from Arel::SelectManager neither from sql string. You have two ways to load data through ActiveRecord:
Do all query logic in Arel. In this case you can't use any of ActiveRecord::Relation methods. But you have same functionality in Arel. In your example you may set limit through Arel:
my_query.take(10)
Other way is to use Arel in ActiveRecord::Relation methods. You may rewrite your query like this:
posts = Arel::Table.new :posts
authors = Arel::Table.new :authors
join = posts.join(authors).
on(posts[:author_id].eq(authors[:id])).
join_sources
my_query = Post.
joins(join).
where(authors[:name].eq('Karl'))
> my_query.class
=> ActiveRecord::Relation
In this case you may use my_query as ActiveRecord::Relation
Right now i'm study a flow of ecommerce site using laravel 5.0 and crinsane laravel package .
I have setup 2 tables
Which is transactions and orders table
The relations is orders has many transactions (1 transaction 1 type of item ) , and transactions belong to orders .
So , in transactions there is foreign key order_id which references to order tables id .
In routes I set route::post('checkout','OrderController#checkoutpost');
public function checkoutpost()
{
// Get input from checkout forms
$input = Request::all();
// Insert forms data into Order table
Order::create($input);
// Retrieve the session data and inserting into Transaction table
$formid = str_random();
$cart_content = Cart::content();
foreach ($cart_content as $cart) {
$transaction = new Transaction();
$products = Product::find($cart->id);
$transaction->product_id = $cart->id;
$transaction->form_id = $formid;
$transaction->qty = $cart->qty;
$transaction->total_price = $cart->price * $cart->qty;
// Here is the problem , how to assign this transaction>order_id into our "id" that just inserted earlier ..
$transaction->order_id = $orders;
$transaction->save();
Cart::destroy();
return redirect('product/checkout');
}
}
The problem is how to assign order_id with the id of data that we just insert earlier?
Any feedback were really appreciated, thank you
Firstly, when creating the Order you need to assign the return value:
// An instance of Order is returned, so the id is accessible.
$order = Order::create($input);
Then you can use:
// Remember to make 'id' a fillable field on the Order model if you want to do it this way.
$transaction->order_id = $order->id;
Have you try this AvoRed an Laravel E commerce its almost fully featured e commerce for Laravel if you like it give it a try and let me know the feedback if you have any.
AvoRed An Laravel E commerce
I am trying to count daily records for some model, but I would like the count was made only for records with some fk field = xy so I get list with days where there was a new record created but some may return 0.
class SomeModel(models.Model):
place = models.ForeignKey(Place)
note = models.TextField()
time_added = models.DateTimeField()
Say There's a Place with name="NewYork"
data = SomeModel.objects.extra({'created': "date(time_added)"}).values('created').annotate(placed_in_ny_count=Count('id'))
This works, but shows all records.. all places.
Tried with filtering, but it does not return days, where there was no record with place.name="NewYork". That's not what I need.
It looks as though you want to know, for each day on which any object was added, how many of the objects created on that day have a place whose name is New York. (Let me know if I've misunderstood.) In SQL that needs an outer join:
SELECT m.id, date(m.time_added) AS created, count(p.id) AS count
FROM myapp_somemodel AS m
LEFT OUTER JOIN myapp_place AS p
ON m.place_id = p.id
AND p.name = 'New York'
GROUP BY created
So you can always express this in Django using a raw SQL query:
for o in SomeModel.objects.raw('SELECT ...'): # query as above
print 'On {0}, {1} objects were added in New York'.format(o.created, o.count)
Notes:
I haven't tried to work out if this is expressible in Django's query language; it may be, but as the developers say, the database API is "a shortcut but not necessarily an end-all-be-all.")
The m.id is superfluous in the SQL query, but Django requires that "the primary key ... must always be included in a raw query".
You probably don't want to write the literal 'New York' into your query, so pass a parameter instead: raw('SELECT ... AND p.name = %s ...', [placename]).