Django search on date field with MySQL DB - django

I have a date field in one of my models. I want to develop a search service, which in user sends a query param as search key, for example '?search=2018' and the response would be all rows in data base that their date's year is 2018. Or if the user sent '?search=11' the response would be all rows that either their date's month is 11, or their date's day is 11.
I am using django 2 and MariaDB version 10.3.18
Here's my model:
class MyDate(models.Model):
name = models.CharField(max_length=255)
date = models.DateField()

From a controller and http request point of view, you cannot use the same parameter for both condition. It would need, for instance, both a search_year and a search_month. They also can be combined together.
From a model and SQL query point of view, the Django documentation about retrieving records with filters might be of help. There is an exemple there about filtering by years.

Related

Select latest record in the group with ordering

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.

Django and Postgres inserting into many-to-many table not working

I'm using python and psycopg2 to scrape some data and insert them into my database.
I've already created the movies and actors tables inside my Django models.py and inside my movies table, there is a many to many relationship between movies and actors table.
below is my models.py:
class Movie(models.Model):
name = models.CharField(max_length=55)
summary = models.TextField(max_length=1024)
actor = models.ManyToManyField(Actor, blank=True)
when I create a movie from Django-admin I select which actors are included in the movie and everything works fine and all the related actors for that movie will show up on my website.
But the problem is that when I try to insert scraped data into my database outside of my Django project folder, the related actors won't be shown on my website because obviously, I have not set the many to many relationship between them.
I have tried creating a junction table using SQL commands which gets the movie id and the actor's id and links them together but I don't know how I should tell Django to use that table and show the related actors for each movie.
This is the SQL code I use to insert into my db:
INSERT INTO movies(name, summary)
VALUES ('movie name', 'sth')
and the code to insert to actors table:
INSERT INTO actors(name, bio)
VALUES ('actorname', 'sth')
Both actors and movies table have auto generated id and I insert them insto the junction table using the code below:
INSERT INTO movie_actors (actor_id, movie_id)
VALUES (
(SELECT actor_id from actors where name='actor name'),
(SELECT movie_id from movie where name='movie name')
)
Am I doing it right?
I would really appreciate it if someone could help me with this.
Django automatically creates a table for many2many relationships. From docs:
ManyToManyField.through
Django will automatically generate a table to manage many-to-many relationships. However, if you want to manually specify the intermediary table, you can use the through option to specify the Django model that represents the intermediate table that you want to use.
The most common use for this option is when you want to associate extra data with a many-to-many relationship.
So you must find the name of the table that django had already created.
Secondly, I suggest that you use django's ORM instead of raw queries so you don't have these kind of problems anymore.
Django automatically creates a through table for M2M relations, if you need you can specify custom through table. In your case I think there is no need of custom through table.
I using Django ORM instead of writing raw query.
INSERT INTO movies(name, summary) VALUES ('movie name', 'sth')
instead of tis raw query you can use the following ORM query:
movie = Movie.objects.create(name="movie name", summary="movie sammuary")
This will create a movie entry in the Movie table.
Next to create user entry you can use the following query:
actor = Actor.objects.create(name="actor name", bio="actor bio")
Now you created the entries in both the table, next you can establish the realtion, for that you have to use the following query:
movie.actor.add(actor)
Incase if you want to add multiple actors at the same time, you create multiple actors object and use following query:
movie.actor.add(actor1, actor2, actor2)
For more details you can check django's offical documentation

How to structure django models and query them with ease?

I am building a Django web App that will count the total number of persons entering and exiting a school library in a day, week and year and then save to DB.
The Web App uses a camera that is controlled by OpenCv to show live feed on frontend (I have successfully implemented this already).
My problem is:
How can I design and structure my models to store each data by day, week, month and year?
And how can I query them to display them on different Bar Charts using chart.js?
I haven't used chart.js before but I think I can answer the first part of your question.
Consider this model from one of my projects for a "post" that a user can make on my webapp.
class Post(models.Model):
slug = models.SlugField(unique=True)
title = models.CharField(max_length=100)
description = models.CharField(max_length=2200)
image = models.ImageField(upload_to=photo_path, blank=False, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
Using a "DateTimeField" (or alternatively a "DateField") you can pretty easily store timestamp information which can be filtered using standard python Date or DateTime object comparisons. In my example, I'm storing image files and text information.
For your case you could simply create a new "Person" model where each person is given a timestamp (and whatever other info you might want to store) and then using django querying you can count how many people match certain datetime parameters.
Note the Django Docs (https://docs.djangoproject.com/en/3.1/ref/models/querysets/) recommend :
Don't use len() on QuerySets if all you want to do is determine the number of records in the set. It's much more efficient to handle a count at the database level, using SQL's SELECT COUNT(*), and Django provides a count() method for precisely this reason.
An example of how I'd approach your problem would be:
Models:
class Person(HabitModel):
timestamp = models.DateTimeField(auto_now_add=True)
#whatever extra data you want on each person walking by
#staticmethod
def get_number_of_people(start_timestamp, end_timestamp):
return Person.objects.filter(timestamp__gte=start_timestamp, timestamp__lt=end_timestamp)).count()
(Note the "__gte" and "__lt" are built-in for Django querying and imply [start_timestamp, end_timestamp) inclusive start time and exclusive endtime)
Now you should be able to store your data rather simply and quantify how many people objects were created in whatever timeframe you'd like!

Serializing an SQL Function in Django REST

I'm using Django and Django Rest Framework to build an API.
I have a custom PostgreSQL function like this: myfunction(from_date, to_date)
It simply calculates a figure from records in the date range in reviews table.
How can I (safely!) take from_date and to_date from URL query parameters, pass them to the function, and return the (float) result via the API?
I have made a simple model to hold the float, like this:
class Result(models.Model):
result = models.FloatField(default=0)
class Meta:
managed = False
Alternatively, could I forgo the SQL function and implement this directly in Django/REST itself?
I already have a model for reviews. In the view for result can I pull reviews from a date range, calculate it, and return the value as a serialized result response?
As an end result, I want to be able to curl http://my.api/result?from=2019-03-01&to=2019-04-01 and get the result.
Thank you.
you can just simple filtering with lte and gte in your review Model and i am supposing date is a field of your Review model where you store record of every review. Then
Review.objects.filter(date__gte=from_date, date__lte=to_date)
Replace date with appropriate field name of your Review model And also with appropriate serializer.

How to add a time stamp for all the fields in a model django

I'm looking to add a new table that records all the user activity in my models. I was able to add a time stamp for general edits, but is there any practical way of adding a new table with the time stamp and the changed field? This would be useful to have as a ledger for all the user activity.
As an example:
if i have a model named blog_post with fields of title and content, how would I back up a history of the changes into a master table with a timestamp and user_id so i could see all the different versions of that blog post with a time stamp and the content change?