Should I create a model to contain another model instances? (Django) - 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)

Related

Django - Many to Many Relationship with Workouts & Exercises

I'm currently stuck on how to do the following:
I want to track workouts and see the progress being made with the exercises.
Each workout has a name, body weight, date, and exercises.
I want to select the exercises when adding the workouts(exercises are already pre-created with a name and some tags), however, each workout is different, meaning the reps, sets, and weight for the exercise is different every time.
I'm not sure how to make a model for this.
I've added an image of a simple design I made to show what I'm after
Hope someone can help me, I'm pretty sure it's a simple solution however, my brain is stuck atm.
Image Of Design
First an foremost, I'd recommend reading through the Django models docs to get an idea of what models represent and how they work.
To address your question, I think you've correctly identified all of the information you need to create your models, so let's go through them step by step.
Architecture
It's helpful to take a step back and think about the entities in your app. Identify what they are, what attributes they posses and which of these attributes are atomic i.e. cannot be their own entity.
Workout - You mentioned that you want to track workouts with each one having name, body weight, date, and exercises. All of these attributes except for exercises seem to be atomic as they can be represented with fundamental datatypes (strings, floats, datetimes etc.). Moreover, one workout can have many exercises indicating that we need to abstract it into its own entity.
Exercise - You identified that exercises are pre-set and need to have a name and tags. A name is something we can represent with a string, however one exercise can have multiple tags, meaning it's not atomic (has a one-to-many relationship). This means we need to extract it into its own entity.
Tag - From what you said, a tag simply has one attribute which is a name that can be represented by a string. One tag can belong to many exercises.
You may be wondering where we are storing the reps, sets and weight data for each exercise in each workout. This is actually going to require an extra entity that stores the many-to-many relationship between Exercise and Workout. Let's call this Workout-Exercise.
With this information we could draw a Entity Relationship Diagram as such:
This gives us what we need to start creating Django models.
Models
Let's start with the Exercise and Tag entities. We can simply translate these directly into Django models:
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=200)
class Exercise(models.Model):
name = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag)
Here we've created the two models and specified a many-to-many relationship between Exercise and Tag. This means that an Exercise object can have many Tag objects e.g. you can call exercise.tags.all() to get all of the tags for a given Exercise object.
The tricky part comes when we are creating the Workout-Exercise entity. When we use ManyToManyField in Django, it normally automatically creates a mapping model/table that we don't see. However, in the case where we want to store extra information about these relations (as we do in our use-case) we have to use a through model.
On this model we have to define the two foreign keys for the models we are linking along with the data types for the extra field data we want to store. In this case the foreign keys are Workout and Exercise, and the extra data are reps, sets and weight. The model definitions could therefore look like:
class WorkoutExercise(models.Model):
workout = models.ForeignKey(
'Workout',
on_delete=models.CASCADE,
)
exercise = models.ForeignKey(
Exercise,
on_delete=models.CASCADE,
)
reps = models.IntegerField()
sets = models.IntegerField()
weight = models.DecimalField(max_digits=5, decimal_places=2)
class Workout(models.Model):
name = models.CharField(max_length=200)
body_weight = models.DecimalField(max_digits=5, decimal_places=2)
date = models.DateTimeField(auto_now_add=True)
exercises = models.ManyToManyField(
Exercise,
through=WorkoutExercise
)
If you're confused about any of the model data type choices I've recommended, please take a look at Django model docs.
With this set-up you should be able to access and insert all of the data you need. If you need more information on how to access any of the many-to-many relationship data, please look at the Django many-to-many docs.
Sources
https://docs.djangoproject.com/en/3.2/topics/db/models/
https://www.1keydata.com/database-normalization/first-normal-form-1nf.php
https://en.wikipedia.org/wiki/One-to-many_(data_model)
https://docs.djangoproject.com/en/3.2/topics/db/examples/many_to_many

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!

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!

Django making field related to other field (object) value

few years ego I worked with Odoo framework. and Odoo has very nice feature like this:
partner_id = field.Many2one(Partner)
partner_name = fields.Char(string='Partner name', related='partner_id.name')
basically whenever you would assign different partner_id from Partner table, partner_name would be assigned automatically. Now I started to work with django (absolute newbie), and I can't seem to find a similar functionality.
My question is what could be possible solution for this problem. Maybe there are already established external libraries that has this sort of functionality?
Expected result:
product = models.ForeignKey(Product)
product_color = models.CharField(string='Partner name', related='product.color')
having in mind that product object would have color field and it would be assigned to product_color whenever product field value Product object color value changes. Also what about storing it to database? Would be nice if there was an option to chose between storing it in database or getting it on the fly.
Cheers!
Creating a getter is pretty easy, because you can simply have functions in a Python object behave as a property:
class SampleModel(models.Model):
product = models.ForeignKey(Product)
#property
def product_color(self):
return self.product.color
This does retrieve the property on the fly, which will cause a call to the database.
Duplicating data, is usually a (more severe) antipattern. Synchronizing data, even in two tables in the same database, often turns out harder than one might expect. Even if you would use Django's signal framework for example, then some Django ORM calls can circumvent that (for example .update(..) [Django-doc]). But even if you somehow would cover those cases, then another program that talks to the database could update one of the two fields.
Most databases have triggers that can help. But again, the number of cases to cover are often larger than expected. For example, if the Product that we refer to is removed, then or the foreign key now points to a different Product, then we will need to update that field.
Therefore it is often better, to fetch the name of the related product when we need it. We can do so by (a) defining a property; or (b) make an annotation, for example in the manager.
Defining a property
We can define a property that will load the related product, and fetch the related name, like:
class Order(models.Model):
product = models.ForeignKey(Product, on_delete=models.PROTECT)
#property
def product_name(self):
return self.product.name
Then we can fetch the product name with some_order.product_name. This might not be very efficient if we need to fetch it often, since the relations are, by default, loaded lazily in Django, and thus can result in an N+1 problem.
Annotate the queryset
We can make an annotation that will fetch the name of the product in the same query when we fetch the Order, for example:
from django.db.models import F
class OrderManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
product_name=F('product__name')
)
class Order(models.Model):
product = models.ForeignKey(Product, on_delete=models.PROTECT)
objects = OrderManager()
Then if we fetch an order. For example with Order.objects.get(pk=1), then that Order object will have an attribute product_name with the name of the product.

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.