How to create one Model (table) for each user on django? - django

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).

Related

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!

Django: how to save model into different database tables depending on which ManyToOne relationship it belongs to?

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.

Design Question: Low load data aggregation for overview page

What is the best way to achieve low load on the database or application server for this use case:
Let's say I want to build a web application that has for each user an overview page. The overview page shows in an aggregated form for each user the user's data. For example, if it were a library application it would show how many times the user visited the library in total, how many books he read in total, how many books were delivered delayed in total, how many minutes he spend in the building. Each time the user visits the overview page the up-to-date values should be displayed. While the user interacts with the site the numbers change.
What I could do is for every overview page refresh do several counts in the database. But that would be expensive.
views.py
def overview(request, userID):
booksCount = Book.objects.count()
booksReadCount = Book.objects.filter(UserID=userID, Status='read').count()
# ... many more, same way
libraryVisitedCount = LibraryVisits.objects.filter(UserID=userID).count()
# many counts like these on different tables for the user
data = {
"booksCount" : booksCount,
"booksReadCount" : booksReadCount,
# ... many more
"libraryVisitedCount" : libraryVisitedCount
}
render(..., context=data)
I have thought I could store a JSON object with the data to be presented on the overview page in a database table and I update the JSON each time an event happend on the site which affects the count of objects.
Or I could use a materiliazed view but to refresh it I would have to recalculate all the data of all users each time, right?
Other ideas? I'm using django webframework and postgres database.
TL;DR: I wondered isn't there a better way to receive counts than do several counts in the database each time?
Thanks.
Lets say, in Book, LibraryVisit etc models, there is ForeignKey to User model with related_name like this:
class Book(models.Model):
UserID = models.ForeignKey(User, related_name='books', on_delete=DO_NOTHING)
class LibraryVisit(models.Model):
UserID = models.ForeignKey(User, related_name='library_visit', on_delete=DO_NOTHING)
Then you can use annotation and conditional expression like this:
from django.db.models import Case, IntegerField, Sum, When
def overview(request, userID):
users = User.objects.filter(pk=userId)
users = users.annotate(
booksReadCount=Sum(
Case(
When(book__Status='read', then=1),
output_field=IntegerField()
)
)
).annotate(library_visited_count=Count('library_visit'))
# FYI: please use snake_case when defining object attribute(like model fields) as per PEP-8 style guide
data = {
"user_object" : users.first(), # taking first item of the User queryset. Also DB is hit once in this step
"booksCount" : Book.objects.count()
}
# access counts in view like this:
# user.book_read_count
# user.library_visited_count
return render(..., context=data)
# bold marked words are related_name
And render counts in template like this:
{{ user_object.book_read_count }}
{{ user_object.library_visited_count }}

How to add Foreign Keys to Django Field History?

I'm trying to track Foreign Keys using django-field-history, but when I add it, it does additional queries on every page using the Model
For example
from field_history.tracker import FieldHistoryTracker
class Author(models.Model):
user = models.ForeignKey('auth.user)
field_history = FieldHistoryTracker(['user'])
will always give more queries on pages using Author, like so
SELECT ••• FROM "auth_user" WHERE "auth_user"."id" = '2'
1239 similar queries. Duplicated 1235 times.
I've tried using user_id instead of user in Field History Tracker, but it will always return None. Using user.id or anything like it just returns an error.
I really need to keep that history data, but not at the cost of thousands of additional queries.
Also, would really enjoy keeping django-field-history as my whole DB is using it, but I'm aware I might have to switch package, and if so, which one would you advise ?
As far as my understanding goes, you are trying to log which user has updated, for this you should use _field_history_user as described in the documentation.
For example:
class Pizza(models.Model):
name = models.CharField(max_length=255)
updated_by = models.ForeignKey('auth.User')
field_history = FieldHistoryTracker(['name'])
#property
def _field_history_user(self):
return self.updated_by
It would always update which user has updated the row for this table.

Joining three or more tables using django ORM

I have designed my models such way that all the models will have one to one relation on auth_user table which is User. For your quick reference I am pasting the Picture below
Now I want to select all the data related to username which are in tables BasicDetails, Department and Project. The below query is not fetching the results.
User.objects.select_related().get(username='user1')
Can someone help me on this?
-Vikram
You should use prefetch_related for efficiency, since your relation is reverse (you want to access the other records from User and not the other way around):
u = User.objects.prefetch_related('project_set', 'department_set', 'basicdetails_set').get(username='user1')
This will not generate a single query, but Django will use caching techniques to effectively produce less possible db overhead. If I recall correctly it will produce 4 queries (a single join in 4 tables might be slower anyway, depending on number of records, indexes etc). The benefit is that on subsequent requests no queres will be generated. For example to get a user's projects:
u.project_set.all() #hits the db
u.project_set.all() #cached version, no db hit
For more info see here https://docs.djangoproject.com/en/dev/topics/db/queries/#one-to-one-relationships.
EDIT: what is project_set?
If your Project model is defined like this
class Project(models.Model):
...
user = models.ForeignKey(User)
then you can do Project.objects.get(pk=1).user to access the user associated to a project instance, but how would you do the opposite (get all projects of a certain user)? Django will automatically include a '_set' property to the other model for convenience. Therefore we can get the projects of a certain user like this:
u = User.objects.get(pk=1)
user_objects = u.project_set.all()
However if you want to explicitly set a name for this reverse relation, django allows you define the ForeignKey with a related_name keyword argument like this:
class Project(models.Model):
...
user = models.ForeignKey(User, related_name='projects')
Now instead of .project_set you could use .projects to access a user's projects:
u = User.objects.get(pk=1)
user_objects = u.projects.all()