I have two models user and recordings, But I don't have any relation between them I have stored user id in recordings (there can be multiple recordings of one user). and I want the latest recording of user with user object how can I achieve that
class Recording(models.Model):
userid = models.IntegerField()
Hi welcome to stackoverflow.
Please ask your question with some of your code.
I think you can try this:
users = User.objects.all().extra( select={
'last_reco':
'SELECT recordings.field_name FROM recordings WHERE '
'recordings.userid = '
'User.id ORDER BY id DESC LIMIT 1',
})
note: recordings is your recording db name
Than you can access last recording with last_reco attr of user object
Related
I am having trouble writing a query using Django ORM, I want to find the latest record in each group. I am putting chat messages in the model and I want to find the latest chat of each user and show chats latest chat of each user and with the latest user's chat on the home screen just like in WhatsApp, Skype or similar apps. Currently, I am using the following query,
Chats.objects.all().order_by('user_id', '-date').distinct('user_id')
Using this I am able to get the latest chat of each user but I am not able to get the sequence correct. The result of the query is in the order of which the users were created in the database which I understand is correct, but I want to show the user who sent the latest chat at the top.
My Models.py
class Chats(models.Model):
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
chat = models.CharField(max_length=1023, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
Thank you so much, Please let me know if any other information is required.
Option 1: Order on the Django/Python layer
The items are first sorted by user_id, and only in case of a tie, it takes the one with the latest date. But that means that you eventually get for each user a Chats object, ordered by the user_id.
I think here your only option is to sort it at the Django/Python level, so wrap it into a list, and sort by the date:
from operator import attrgetter
items = list(Chats.objects.order_by('user_id', '-date').distinct('user_id'))
items.sort(key=attrgetter('date'), reverse=True)
# work with items
and then render the items in the template.
Option 2: Annotate the User model instead
Another option is to annotate the User model and thus work with a QuerySet of User objects:
from django.db.models import Max, OuterRef, Subquery
User.objects.filter(
chats__isnull=False
).annotate(
last_date=Max('chats__date'),
last_message=Subquery(
Chat.objects.filter(user_id=OuterRef('pk')).order_by('-date').value('chat')[:1]
)
).order_by('-last_date')
Here the User objects will have an extra attribute .last_date with the latest date time of the object, and .last_message with that message.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I'm new to Django. My app have two models, Customer and Order, where each customer can have multiple orders. So what I did is to set up a ForeignKey(Cusotmer) relationship in Order model:
name = models.CharField(max_length=20)
phone = models.CharField(max_length=20)
def __str__(self):
return self.name
class Order(models.Model):
customer= models.ForeignKey(Customer,null=True, on_delete = models.SET_NULL)
ordername = models.CharField(max_length=20)
In this case, if I want to query the orders by a specific customer customer1, I can use Order.objects.filter(Customer=customer1). But I wonder if it is possible to save the order data for each customer in a separate database table? Right now all the orders are saved in the same table and misuse of filters can let customers view other customers' orders.
But I wonder if it is possible to save the order data for each customer in a separate database table?
Even if this were possible, you definitely do not want to store each customer's orders in a separate database table. Relational databases are designed for data with the same structure to be stored as rows in a table, and that's how Django models (which define the structure of your data) expect to interact with your database.
The correct approach is to save all customers' orders in a single table, using your Order model, and use the Django ORM to filter based on the user.
Right now all the orders are saved in the same table and misuse of filters can let customers view other customers' orders.
Even if you used separate tables for each customer's orders, you would still need to determine which table's data to display to the user (just like how with all the orders in a single table, you have to determine which rows to use). If you use the Django ORM correctly (to filter the data based on the user who makes the request), this is a non-issue.
Task Details
I am working on creating a custom API to fetch data from three tables, based on provided key info.
Background
To elaborate, I've three data tables - Client, Account and Client_accounts and their structure looks like this:
Client
ID (Integer) Primary Key
display_name (varchar)
Accounts
ID (Integer) Primary Key
nickname (varchar)
Client_Accounts
Client_ID (Integer) Foreign Key -> ID from client table
Account_ID (Integer) Foreign Key -> ID from accounts table
In intend to pass a client ID to my API and want to fetch all the accounts (and accounts names) owned by that client.
The SQL query that I am trying to replicate looks like this:
select
cl.id as client_id,
cl.display_name,
ac.id as account_id,
ac.nickname as account_name
from
datahub_clients cl
join
datahub_client_accounts cl_ac
on
cl.id=cl_ac.client_id
join
datahub_accounts ac
on
cl_ac.account_id=ac.id
where
cl.id=15
;
Done so far
This is what I used to fetch the the accounts for a client:
##### For endpoint - get_client_name
#api_view(['GET', 'POST'])
#permission_classes((AllowAny,))
def get_client_name(request):
try:
if request.method == 'GET':
list_of_account_ids = Client_Accounts.objects.filter(client_id=request.GET['id']).values_list('account')
needed_accounts = Accounts.objects.filter(id__in=list_of_account_ids).values('id','nickname')
return Response({'requested client id':request.GET['id'],'identified client name': 'detailed info to go here'}, status=status.HTTP_200_OK)
else:
return Response({'status':'error','message': 'Facepalm moment!'}, status=status.HTTP_403_FORBIDDEN)
Problem Statement
1) In the code above, I was able to pull the relevant accounts for a client_id, however, I can only print the details from account table. How do I put client information as well in the output (client_id, nickname - as shown in the SQL query)
2) What is the django replacement for SQL 'old_field_name AS some_new_name'? In the data tables shown above, both the account and client tables have an 'ID' column. I want to put them both together in the same JSON output and to be able to distinguish between then, I would want to rename them.
3) At this point, my queryset has field members from multiple models. How do I serialize them? I understand that I need to write a custom serializer, which would be based on the two models (for the example show above). I am confused about what to specify in the model= section and meta: section.
I am using Django and rest-auth. I already have a working code to fetch today's and yesterday's login counts in my Django application as follows:
def get_analytics(request):
total_users = User.objects.all().count()
total_users_games = User.objects.filter(username__startswith='yg_').count()
# Number of users who dogged in once to our system today
today_login_count= User.objects.filter(last_login__startswith=timezone.now().date()).count()
today_login_count_memoryGames= User.objects.filter(last_login__startswith=timezone.now().date(), username__startswith='yg_').count()
yesterday_login_count = User.objects.filter(last_login__startswith=timezone.now().date() - timezone.timedelta(days=1)).count()
yesterday_login_count_memoryGames = User.objects.filter(last_login__startswith=timezone.now().date() - timezone.timedelta(days=1), username__startswith='yg_').count()
There are usernames starting with 'yg' and few starting with 'yg_' responsible for two different frontends.
Today's login count is correct, I crosschecked from database. However I am not sure about yesterday's login count, it looks like the number which I get is not correct (i.e. today's login count will be tomorrow: yesterday's login count, so these numbers should be same). I suspect the code for yesterday's login count gives me those users who did login yesterday and not today, where as what I want is all the users who logged in yesterday. I ran following query with yesterday's date and got 4 results and that's actually what
yesterday_login_count_memoryGames = User.objects.filter(last_login__startswith=timezone.now().date() - timezone.timedelta(days=1), username__startswith='yg_').count()
gives me.
select username, last_login from auth_user where username like '%yg\_%' and last_login like '%2016-09-06%';
I am cross checking in my database with following sql query:
select username, last_login from auth_user where username like '%yg\_%' and last_login like '%2016-09-07%';
How can I write a query to fetch yesterdays's login count like this?
Also, in this line username__startswith='yg_' do I need escape character? like username__startswith='yg_'? to get the count of logins with usernames starting with yg_?
Relying on last_login isn't going to cut it and will give unreliable data. You will need to store each successful login event in another table foreign keyed to the user along with the login time.
class LoginEvent(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
login_date = models.DateField()
Note that you wont need to store more than one login in a day. When a user logs in, check if an entry with todays date exists or not. If it exists, then do need not do anything. If it doesn't exist, you will need to insert a new row with todays date. You could even set up a unique_together constraint for ('user', 'login_data') to enforce this.
After this, the following query will be able to give you the login count data you need.
yesterday = timezone.now().date() - timedelta(days=1)
LoginEvent.objects.filter(login_date=yesterday, user__username__startswith='yg_').count()
This will create the necessary inner join and give you the counts.
I have a Model, and want every User of the system has a table reserved for himself, respecting this Model.
To make it clear:
Imagine the Model "Games".
I do not want that there is only one table "games", but there is:
foo_games, bar_games (foo / bar are users of the system)
How to do this ?
edit:
why ?
Imagine I have 1000 users, and each User has 100 games.
Do you think you have a table with 1000 * 100 items is better than having 1000 tables with 100 items each?
The way this is typically handled in with the Django ORM is by linking the two models together (tables) with a Foreign Key. You can then get just the records that apply to a user by using the .filter() method. In this way it will seem like each user has their own table. For example...
from django.contrib.auth.models import User
from django.db import models
class Game(models.Model):
name = models.CharField(max_length=50)
owner = models.ForeignKey(User)
The ForeignKey field here provides a "link" that relates 1 Game record to a specific User.
When you want to retrieve the Games that apply just to 1 user, you can do so like this:
# Select whichever user you want to (any of these work)
user = User.objects.get(username='admin')
user = User.objects.get(id=64)
user = request.user
# Then filter by that user
user_games = Game.objects.filter(owner=user)
Edit --
To answer your question about more rows vs. more tables: Relational database servers are optimized to have a huge row capacity within a single table. With your example query, 1000 * 100 is only 100,000 records, which is probably only 0.01% of what a table can theoretically hold (server memory and storage aside).