Django Sort by backward foreign key - django

I currently have the following models
class ChatRoom(models.Model):
creator = models.ForeignKey('User') # points to the initial user
class Message(models.Model):
room = models.ForeignKey('ChatRoom')
text = models.CharField(max_length=500)
date = models.DateTimeField()
from = models.ForeignKey('User') # points to some user
For any given user who logs into my website, I want to display a list of the chat rooms they have created, ordered by the date of their last message (latest activity) along with the last message entered to the chatroom
So something like
Your chat rooms
---------------
science - "hey guys, anyone know how to do calculus?" 5m
art - "hey guys, I like art" 10m
How would I perform this query in django? Keep in mind that a person might have many, many, many chat rooms and thus we can't just load all the chat_rooms with ChatRoom.objects.all() and manually iterate through it.

You need to have a additional relation to your last message, otherwise you will not be able to order by them.
class ChatRoom(models.Model):
creator = models.ForeignKey('User') # points to the initial user
# you will need to set this in view or with signals.(don't forget to handle delete)
last_message = models.ForignKey('Message')
And that you can do this
ChatRoom.objects.filter(...).order_by('last_message__date')

Related

Populating django model with objects from other model

I'm new to django, but working on an app for a volunteer sailing organization in my local area. Not sure how to ask this question since it's fairly general but I want the following to happen based on two models;
Yacht class (boat name, skipper, color, etc.)
Race_Event class (event date, time results for each boat)
Step 1: The user will need to create a Race_Event each week. I want the boats from the Yacht model to be loaded into the Race_Event.
Step 2: The user will enter race times for each boat.
Is there a way to pre-load objects from one model into another? With a ForeignKey the user has to add the boats each time. Any direction for me to research would be helpful.
Here is the simplified code so far;
class Yacht (models.Model):
yacht_classes = [('A', 'A'),('A1', 'A1'),]
yacht_type = [('J-29','J-29'),('J-24','J-24'),]
yacht_name = models.CharField(max_length=75)
yacht_type = models.CharField(max_length=25, choices=yacht_type,
default='J-29')
yacht_class = models.CharField(max_length=25, choices=yacht_classes)
skipper = models.ForeignKey(Skipper, on_delete=models.CASCADE)
def __str__(self):
return self.yacht_name
class Event (models.Model):
race_date = models.DateTimeField(default=timezone.now)
#yachts = #how to Include Yacht.objects.all() to the field?
class Results (models.Model):
pass
Thanks
Yes, u can use signals...
after objects is saved u can call post_save and add all yachts to race
more => https://docs.djangoproject.com/en/3.1/ref/signals/#post-save
but i dont think this is good way...
(not every time all the data must be present or must be saved => this save rows in database)
i recomment you to use m2M between race and ship with throught table where time is saved in table between.
then its on you how you present this problem to end-user.
with this solution you save only data which are needed.
this can be done with
https://docs.djangoproject.com/en/3.1/topics/db/models/#extra-fields-on-many-to-many-relationships

Django - Database querying - Checking if a list of values is a subset of another list

I'm programming a website aimed at teaching a language. The idea is that by validating lessons, the students are unlocking other contents (exercises, songs...). Formally, at each lesson are attached tags. Whenever students validate a lesson, they validate the associated tags. Each content is flagged with prerequisites corresponding to those tags.
On a page, I want to display all the songs users can get access to based on the tags they unlocked. If they unlocked all the tags associated with the song, they can view it; otherwise they can't.
Here is the model of a lesson (called cours) :
class Cours(models.Model):
niveau=models.ForeignKey(Niveau,on_delete=models.CASCADE)
titre=models.CharField(max_length=255, unique=True)
tags=models.ManyToManyField(Tag)
Here is the model of a song :
class Chanson(models.Model):
titre=models.CharField(max_length=255, unique=True)
prerequis=models.ManyToManyField(Tag,blank=True,related_name="+")
Here is the model of the profile of a user and the solution I found out to answer my problem using Python built-in sets.
class Profil(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
cours_valides=models.ManyToManyField(Cours)
chanson_valides=models.ManyToManyField(Chanson)
def songs_to_do(self):
songlist=Chanson.objects.exclude(id__in=self.chanson_valides.values_list('id',flat=True))
outputsonglist=list()
for song in songlist:
if set(song.prerequis.values_list('id',flat=True))<=set(self.cours_valides.values_list('tags',flat=True)):
outputsonglist.append(song)
return outputsonglist
The songs to do method basically returns the list of songs users have not covered yet but can access based on the lessons they validated so far. Indeed, the cours valides field lists all the lessons validated by users while the chansons valides field lists all the songs already covered by the users.
I wanted to know if there is a more efficient way to treat this kind of problem ?
I would perform 2 queries:
Get all the tags the users does not own:
locked_tags = Tag.objects.exclude(cours__profil=self)
Find all the songs which have a tag the user has not unlocked yet:
unlocked_songs = Chanson.objects.exclude(prerequis__in=locked_tags)
Your code would look like this:
class Profil(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
cours_valides=models.ManyToManyField(Cours)
chanson_valides=models.ManyToManyField(Chanson)
def unlocked_songs(self):
locked_tags = Tag.objects.exclude(cours__profil=self)
return Chanson.objects.exclude(prerequis__in=locked_tags)

Creating a query with foreign keys and grouping by some data in Django

I thought about my problem for days and i need a fresh view on this.
I am building a small application for a client for his deliveries.
# models.py - Clients app
class ClientPR(models.Model):
title = models.CharField(max_length=5,
choices=TITLE_LIST,
default='mr')
last_name = models.CharField(max_length=65)
first_name = models.CharField(max_length=65, verbose_name='Prénom')
frequency = WeekdayField(default=[]) # Return a CommaSeparatedIntegerField from 0 for Monday to 6 for Sunday...
[...]
# models.py - Delivery app
class Truck(models.Model):
name = models.CharField(max_length=40, verbose_name='Nom')
description = models.CharField(max_length=250, blank=True)
color = models.CharField(max_length=10,
choices=COLORS,
default='green',
unique=True,
verbose_name='Couleur Associée')
class Order(models.Model):
delivery = models.ForeignKey(OrderDelivery, verbose_name='Delivery')
client = models.ForeignKey(ClientPR)
order = models.PositiveSmallIntegerField()
class OrderDelivery(models.Model):
date = models.DateField(default=d.today())
truck = models.ForeignKey(Truck, verbose_name='Camion', unique_for_date="date")
So i was trying to get a query and i got this one :
ClientPR.objects.today().filter(order__delivery__date=date.today())
.order_by('order__delivery__truck', 'order__order')
But, i does not do what i really want.
I want to have a list of Client obj (query sets) group by truck and order by today's delivery order !
The thing is, i want to have EVERY clients for the day even if they are not in the delivery list and with filter, that cannot be it.
I can make a query with OrderDelivery model but i will only get the clients for the delivery, not all of them for the day...
Maybe i will need to do it with a Q object ? or even raw SQL ?
Maybe i have built my models relationships the wrong way ? Or i need to lower what i want to do... Well, for now, i need your help to see the problem with new eyes !
Thanks for those who will take some time to help me.
After some tests, i decided to go with 2 querys for one table.
One from OrderDelivery Queryset for getting a list of clients regroup by Trucks and another one from ClientPR Queryset for all the clients without a delivery set for them.
I that way, no problem !

How to make a filter so as to have two entries for each user?

I have model:
class MyModel(models.Model):
user = models.ForeignKey(user)
data = models.IntegerField()
created = models.DateTimeField(default=datetime.now)
[...]
How to make a filter so as to have result of 10 entries with two for each user and then all sorted by "user"?
Example:
Display page "users entries" where are the two latest entries per user.
I'm a django newbe, but recently I had similar problem.
Maybe it will make it for You.
I had users based on django User model and Movies with field owner. I wanted to display last 2 movies of every user, grouped by users and sorted by movie publication date.
What I did, was:
Create and add method to User model (it returns list of 2 movies of user):
from django.contrib import auth
def get_users_last_movies(self):
movies = Movies.objects.filter(state=3,
pubdate__lte=datetime.now(),
owner=self).order_by('-pubdate')[0:2]
return movies
auth.models.User.add_to_class('get_users_last_movies', get_users_last_movies)
in view file select all Users your interested in and append their movies to them, use sort method on created user list
dusers = User.objects.filter(is_active=True)
users = []
for duser in dusers:
duser.movies = duser.get_users_last_movies()
users.append(duser)
users.sort(key=lambda x: x.movies[0].pubdate, reverse=True)
data['dusers'] = users
Hope that this code will get You on track

exclude a query result in another query

Here i want to do is that ,i want to list all the person who didn't blocked me.Here in the table Blocked there is two columns name
who and whose . In whose column i store the id of the person whom i blocked and in the who column i store my id. Now i want to do that, when the blocked person click on
view-person button in my web page he cannot see profile of the person one who blocked him.
when i did this query blocked_list = Blocked.objects.filter(whose = user_id). Now i got the list of the persons who blocked me. Now i want to exclude all this person from this query total_profiles = persons.objects.all().exclude(blocked_list). How can i do this.
models.py
class persons(models.Model):
full_name = models.CharField(max_length=200)
class blocked(models.Model):
who = models.ForeignKey(persons)
whose = models.IntegerField(null=True)
views.py
def blocked(request):
blocked_list = Blocked.objects.filter(whose = user_id)
total_profiles = persons.objects.all().exclude(blocked_list)
return render_to_response('profiles/view_all.html', {'total_profiles':total_profiles,'}, context_instance=RequestContext(request),)
please correct the question if it is not correct.
You can try this:
total_profiles = persons.objects.all().exclude(id__in = blocked_list.values_list('id', flat=True))
It's untested, but adapted from this answer.
Some notes:
if persons has the default manager, you can omit all().
whose does not have an index, so it will become slow when your dataset gets big. You can use a ForeignKey field instead of an IntegerField
the common convention is to capitalize class names and to write model names in singular i.e. Person instead of persons