How to structure django models and query them with ease? - django

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!

Related

Should I create a model to contain another model instances? (Django)

I'm new to django so I'm not sure of the proper way to do things (or the convention).
Say I want to make a project which contains my everyday notes.
I'm going to create multiple notes every day (where each note is going to be an instance of a "Note" model).
I want in my project-frontend to have containers, where I start with containers, each of a specific year (say 2020, 2021, ...) and each of these containers contains month containers (Jan, Feb, ...) and each of those contains day containers (1, 2, ..) and each of those contains the notes of this specific day.
Now my question is should, in my backend, make a NoteYear model which has instances of a NoteMonth model which has instances of NoteDay model which has instances of Note model?
I understand that I can filter the objects by the DateTimeField, and put them in different containers in the frontend (Of course I'll have a DateTimeField for each Note instance anyways).
The reason I thought of this is because it should be faster filtering to get to a specific day.
I'd love to hear your opinions!
Models should not be written based on how to present data at the front-end. Models should try to represent and store data in an effective manner.
Here it would be pure fabrication to create models for the year, month and day items. A simple Note model with a DateTimeField should suffice, especially if you add a database index to that field such that it can easily filter.
Such model thus looks like:
from django.db import models
class Note(models.Model):
note = models.TextField()
created = models.DateTimeField(auto_now_add=True, db_index=True)
You can then effectively retrieve items for a given year, month, day with:
Note.objects.filter(created__year=2021) # year
Note.objects.filter(created__year=2021, created__month=9) # month
Note.objects.filter(created__year=2021, created__month=9, day=25) # day
You may use models as storage objects which means you don't have to define your models based on each and every container.
Accordingly, you may define you models as follows and use django-template to iterate and filter by dates into years/months/days.
class Notes(models.Model):
title = models.CharField(max_length=200)
created = models.DateTimeField(default=timezone.now)
updated = models.DateTimeField(default=timezone.now, blank=True)

How can I create a model that represents a spreadsheet?

I am trying to build a table style app to allow tracking items in a spreadsheet that can be added to a branded website. My table would look something like this if using a spreadsheet:
Customer Name
Customer Address
Producer
Mark
233 Main St
Greg
Company
Date Ordered
Rep
Date Received
Cost
Quote Number
A
7/20/21
John
7/25/21
500
JDHP
B
7/20/21
Mary
C
7/23/21
John
7/25/21
1500
584D
D
7/18/21
Mary
7/22/21
400
J5HP
Effectively the idea is that I'd have a model that houses each Customer's different quotes. I have 2 categories of companies (public and private) that would each be tracked so I'm envisioning a large form that houses these three small forms (customer info, private company quotes and public company quotes). I would be including every company in every sheet whether we reach out to them for a quote or not so we know what options are still available if the customer requests more quotes.
I've been looking at the django formsets as a possible option but don't fully understand how they work. I watched some tutorials and read through the documentation but it seems like those will simply add a blank input after all complete ones already in the table. Is this a correct interpretation of how formsets work? Or would they effectively allow me to nest multiple forms within a larger form? Secondary to that is how would I implement this model? I tried company_date_ordered, company_rep, company_date_received, etc. for each company in my list but got a lot of clash errors.
Welcome to web development.
A few points:
It's been said, "Applications age like fish, data ages like wine" - what this means is its best to focus your attention on your data models and concern yourself less with the application code itself
Spreadsheets are themselves tables - meaning you wouldn't build a model that represents a spreadsheet but rather you would build a model that represents a row (object) or elements of each row (objects) of the spreadsheet
That being said, given your example let's consider what objects we are working with:
Your first "spreadsheet" looks like it could be a combination of a Customer and Producer table - for this example we will simplify this to just a Customer table which will contain the field producer
Your second spreadsheet is a bit more complex, it appears to join Company, something like an Order and possibly a Representative (and maybe even more) - let's break this down into each of its parts:
models.py
class Customer(models.Model):
"""
this is a simple model that represents a customer,
it doesn't have any relations to other tables
"""
name = models.CharField(...)
address = models.CharField(...)
producer = models.CharField(...)
class Order(models.Model):
"""
this table represents orders,
it will have relations to other tables, add them as needed
"""
# fields:
date_ordered = models.DateField(...)
date_received = models.DateField(...)
quote_number = models.CharField(...)
"""
an Order can only be associated to one Company
but a Company can have many Orders
therefore we will use a ForeignKey
the same goes for Representative
"""
# relations:
company = models.ForeignKey("Company", ..., related_name = "orders")
representative = models.ForeignKey(...)
class Company(models.Model):
"""
this model represents a Company
its related to Orders,
but the relation is defined on the Orders table
"""
name = models.CharField(...)
class Representative(models.Model):
...
Spend some time thinking about what your entities are and how they relate to one another. Once your data structure is well formed, you can start to build out interfaces for users to view, edit, and add to your tables - forms are a good way to start but they are certainly not the only option. Best of luck!

Caching list of id's of django queryset, and reusing that list for another Viewset

Let's use these 4 simple models for example. A city can have multiple shops, and a shop can have multiple products, and a product can have multiple images.
models.py
class City(models.Model):
name=models.CharField(max_length=300)
class Shop(models.Model):
name = models.CharField(max_length=300)
city = models.ForeignKey(City, related_name='related_city', on_delete=models.CASCADE)
class Product(models.Model):
name=models.CharField(max_length=300)
description=models.CharField(max_length=5000)
shop=models.ForeignKey(Shop, related_name='related_shop', on_delete=models.CASCADE)
class Image(models.Model):
image=models.ImageField(null=True)
product=models.ForeignKey(Product, related_name='related_product', on_delete=models.CASCADE)
For an eCommerce website, users will be writing keywords and I filter on the products names, to get the matching results. I also want to fetch together the related data of shops, cities and images, relevant to the products I will be showing.
To achieve that I am using .select_related() to retrieve the other objects from the foreignKeys as well.
Now, my question is, what is the best way to send that to the client?
One way is to make a single serializer, that groups all data from all 4 tables in a single JSON. That JSON will look like 1NF, since it will have many repetitions, for example, there will be new row for every image, and every shop that the product can be found, and the 10.000 character long description will be repeated for each row, so this is not such a good idea. More specifically the fields are: (product_id, product_name, product_description, product_image_filepath, product_in_shop_id, shop_in_city_id)
The second approach will use Django queryset caching, which I have no experience at all, and maybe you can give me advice on how to make it efficient.
The second way would be to get Product.objects.filter(by input keywords).select_related().all(), cache this list of id's of products, and return this queryset of the viewset.
Then, from the client's side, I make another GET request, just for the images, and I don't know how to reuse the list of id's of products, that I queried earlier, in the previous viewset / queryset.
How do I fetch only the images that I need, for products that matched the user input keywords, such that I don't need to query the id's of products again?
How will the code look like exactly, for caching this in one viewset, and reusing it again in another viewset?
Then I also need one more GET request to get the list of shops and cities, where the product is available, so it will be fantastic if I can reuse the list of id's I got from the first queryset to fetch the products.
Is the second approach a good idea? If yes, how to implement it exactly?
Or should I stick with the first approach, which I am sceptical is the right way to do this.
I am using PostgreSQL database, and I will probably end up using ElasticSearch for my search engine, to quickly find the matching keywords.

Resetting table values through DateTime in Django

I am attempting to create a voting database with an increasing number of names that are never deleted or reset. Votes are cast in the morning, and voting is closed around 10:00. I want to have a separate view that resets the votes back to zero for each instance in the afternoon, after the process is over. How might I accomplish this? Will I have to manually visit this view every day or can it be automated with a DateTime field as the parameter? I have a model to archive old results, but I want to re-use the voting models every day.
class restuarant(models.Model):
name = models.CharField(max_length=50)
votes = models.IntegerField()
percent = models.DecimalField(max_digits=23, decimal_places=20)
def __unicode__(self):
return self.name
class totalVotes(models.Model):
total = models.IntegerField()
class restuarantVote(models.Model):
#voting model for statistic information
choice = models.CharField(max_length=50)
totalVotes = models.IntegerField()
created = models.DateField()
def __unicode__(self):
return self.choice
as andrew suggested resetting data might not be the best approach.
Storing just the raw vote could provide a number of benefits:
you wouldn't have to worry about resetting the data each day. (which could require a cron job to update)
you could analize the data in any way you want.
it is more extendable. You can build more flexible system, suppose you want to add user to the vote to track what a particular user likes?
That way you can see the vote for ANY day not just the current day. You could change up your model:
class Vote(models.Model):
choice = models.CharField(max_length=50)
created = models.DateField(auto_now_add=True)
throughout the day you could just add a vote when one is received
new_vote = Vote(choice=the_choice)
new_vote.save()
then to get the days vote:
todays_count = Vote.objects.filter(choice=the_choice, created=date_obj_here).count()
The best solution to this kind of problem is almost always to eliminate the need for resets entirely. If you can't figure out how to do this conceptually, consider posting more details on your model and application and what you mean by "resetting the votes".
If you absolutely need to run some kind of process daily to clean up your database, you can write a python script and import your application's settings and model file, and then run thej python script with cron on the server. There are a few other too-clever solutions, but almost always you should reconsider your design first.
Edit: now that the code has been added to the question: I recommend you make each restaurantVote represent a single vote cast by a unique individual, and remove the totalVotes IntegerField. Create a new restaurantVote object for each vote cast. You can add a datetime or date field to restaurantVote to mark when it was cast. When you want to total votes, do a query to total up the number of votes for each choice between the beginning and the end of a given day, or just for the given day if you are using a date field instead of a datetime field.
If you don't want to do that, you can keep the IntegerField on there but just add the date field. Every time someone votes, look to see if there is a restaurantVote for that choice and the current day already; if not, then create it (you may be able to use get_or_create() for this).
By the way, if restaurantVote is supposed to be a vote cast for an individual restaurant, then you can use a foreignkey relationship instead of a CharField for choice.

Django and computed fields in a legacy database

I am gradually replacing a legacy database front end with a django based system. All models are Managed = False, to preserve the original db structure.
However I have struck a problem where a field in a table is computed. The field is defined in (pseudo) sql as full_name = fname|| ||lname.
I can define the full_name field as a charfield; and I can read it no problems, however any attempt to update the record results in an update error on that field.
I can use a #property; but that replicates the functionality in django, rather than displaying the results from the db itself. Using this approach will cause problems with more complex fields (in tables I am yet to get to) that are defined with UDFs.
What is really needed is a 'read_only' or 'computed' attribute on the model itself; what is the best way to achieve this?
Do you just want to define a method in your class? Something like:
def Person(models.Model):
fname=models.CharField(...)
lname=models.CharField(...)
def fullname(self):
return self.fname+" "+self.lname
(not exactly sure what Managed=False means...)
if you are trying to make calculation on a database models and pass the value of a model field to another model field of the same class model, using a defined function then this solution might help you. for example lets assume you have an investment company and you give 20% per month for the capital each user invested, you would want want to pass value from capital model to a function that calculates the percentage interest, and then you will pass that function into another field monthly_payment and get saved in the database.
1) pip install django-computed-property
2) add 'computed_property' to your installed apps in project settings.
3) in your models.py, import computed_property then
class Investment(models.Model):
name = models.CharField(max_length=200)
capital = models.FloatField(null=False)
percentage = models.CharField(max_length=5)
duration = models.CharField(max_length=10, default="1 months")
monthly_payment = computed_property.ComputedFloatField( compute_from='monthly_percentage', null=False, blank=False)
then your function to perform the calculation will go thus
#property
def monthly_percentage(self):
return (20 / 100) * self.capital
Note: what i discovered was if you use the inbuilt django fields be it FloatFiled or IntegerField, this function won't read the amount you are passing in to get your 20% calculations.i hope this works for you as i stated all as they worked for me,cheers.