Django: How to get count of a specific column according to two columns - django

i want to get the count of the user id of this table according to the columns approval_transaction_type and approval_type.
the expected result of this would be.
Approval Transaction Type ID (60)
Approval Type ID (65) = 2 Users
Approval Type ID (64) = 2 Users
Approval Type ID (63) = 2 Users
Approval Type ID (62) = 2 Users
Approval Type ID (61) = 2 Users
My current code to achieve is this, but it overwrites the sub list and returns the incorrect result(Which i don't understand why the last array will overwrite all the array):
for transaction in transaction_types:
# Initial Array
transaction["approval_types"] = []
for approval_type in approval_types:
# Get Count of Users
approval_type["count"] = Model.objects.filter(approval_transaction_type=transaction['id'],approval_type=approval_type['id']).values().count()
# Assign this sub list to main list
transaction["approval_types"].append(approval_type)
How do i get the count without looping and use the queryset?
Let me know if something is not clear about this. Thanks!

It can be done in one query. Based on this Django equivalent for count and group by
Model.objects.values('approval_type').annotate(Count('user'))

Related

Django query ForeignKey Count() zero

I have 3 tables:
Truck with the fields: id, name....
Menu with the fields: id, itemname, id_foodtype, id_truck...
Foodtype with the fields: id, type...
I want to get a summary like:
id name total
10 Alcoholic drink 0
5 Appetizer 11
My problem is to return the results with 0 elements.
I tried an SQL query like this:
SELECT
ft.id, ft.name, COUNT(me.id) total
FROM
foodtype ft LEFT JOIN menu me
ON ft.id = me.id_foodtype
LEFT JOIN truck tr
ON tr.id = me.id_truck AND tr.id = 3
GROUP BY ft.id, ft.name
ORDER BY ft.name
or a query in Django
Menu.objects.filter(id_truck=3).values("id_foodtype").annotate(cnt=Count("id_foodtype"))
But, neither is displaying the results with Zero elements.
At the moment to convert this query to Python code, any of my queries return the exact result that I expected.
How can I return results with the Left Join including the foodtypes with zero elements in the menu?
The direction of LEFT JOIN depends on the object, where you start the query. If it start on Menu you will never see a FoodType unused by selected Menu items. Then is important to filter (by Truck in your case) such way that also null value Menu.id is allowed in order to can get Count == 0.
from django.db.models import Q
qs = (
FoodType.objects
.filter(Q(menu_set__id_truck=3) | Q(menu_set__id__isnull=True))
.values() # not necessary, but useful if you want a dict, not a Model object
.annotate(cnt=models.Count("menu_set__id"))
)
Verify:
>>> print(str(qs.query))
SELECT foodtype.id, foodtype..., COUNT(menu.id) AS cnt
FROM foodtype
LEFT OUTER JOIN menu ON (foodtype.id = menu.id_foodtype)
WHERE _menu.id_truck = 3 OR menu.id IS NULL)
GROUP BY foodtype.id
It works with the current newest and oldest Django 2.0b1 and 1.8.
The query is the same with or without the line .values(). The results are dictionaries or FoodType objects with a cnt attribute.
Footnotes:
The name menu_set should be replaced by the real related_name of foreign key id_foodtype if you have defined the related_name.
class Menu(models.Model):
id_foodtype = models.ForeignKey('FoodType', on_delete=models.DO_NOTHING,
db_column='id_foodtype', related_name='menu_set'))
...
If you start a new project I recommend to rename the foreign key to a name without "id" and the db_column field is with "id". Then menu_item.foodtype is a Food object and menu_item.id_foodtype its id.

Laravel 5 checkout form insert foreign key into transaction table

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

Rails pluck error

error undefined method `pluck' for # User:0x00000007234e28
I want to get the details of the last two registered users.
def index
if User.exists?
user1 = User.first.pluck(:id)
user2 = User.second.pluck(:id)
end
end
To solve your problem you can do the following
def index
last_two_users = User.order(created_at: :asc).limit(2).pluck(:id)
end
You can sort on the created_at column if you have one, or on the id column. If you use the id column change asc to desc.
A different way is to use map:
last_two_users = User.last(2).map(&:id)
The last_two_users will have the last 2 users added to your table.

ProgrammingError: when using order_by and distinct together in django

I have a model like below
class ProductScore(models.Model):
client = models.ForeignKey(User)
created = models.DateTimeField(default=datetime.datetime.now)
score = models.IntegerField()
scale = models.ForeignKey(Product)
As of now i am using the below query to filter out the duplicates from the above model
scores = ProductScore.objects.filter(client=request.user).distinct('scale')
By the above query it was returning the unique results but are old(created date was very old), i mean for example if the above table ProductScore has 10 duplicate records in which 5 of them are created yesterday and 5 of them are created today, the above query is returning 5 unique records which are created yesterday.
But i want the records which are created mostly recently(i.e., today) and unique so i tried like below
scores = ProductScore.objects.filter(client=request.user).order_by('created').distinct('scale')
which was not working and throwing some programming error exception
*** ProgrammingError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
LINE 1: SELECT DISTINCT ON ("product_productscore"."scale...
^
So how can i get the most recently created unique records form the above table ?
PostgreSQL is asking you to do this:
ProductScore.objects.filter(client=request.user).order_by('scale', '-created').distinct('scale')
...ordering by -created will give you the most recent of each duplicate, though your overall query results will be ordered by scale field

Latest post by different users

Post has user and date attributes.
How can I turn this
posts = Post.objects.order_by('-date')[:30]
to give me 30 or less posts consisting of the last post by every user?
For example if I have 4 posts stored, 3 are from post.user="Benny" and 1 from post.user="Catherine" it should return 1 post from Benny and 1 from Catherine ordered by date.
I would probably use annotate, you might be able to use extra to get down to a single query.
posts = []
for u in User.objects.annotate(last_post=Max('post__date')).order_by('-last_post')[:30]:
posts.append(u.post_set.latest('date'))
You could also use raw, which would let you write a SQL query, but still return model instances. For instance:
sql = """
SELECT * FROM app_post
WHERE app_post.date IN
(SELECT MAX(app_post.date) FROM app_post
GROUP BY app_post.user_id)
ORDER BY app_post.date DESC
"""
posts = list(Post.objects.raw(sql))
untested but you might be able to do this
from django.db.models import Max
Post.objects.all().annotate(user=Max('date'))