Creating hierarchical database in Django admin site - database

The flow I am working on has
A Product Table, categorized using a Category Table
A Optional Items Table, listing options of the product master hierarchically.
Analogy - Consider a shopping cart with a hierarchical structure as follows -
Laptops & Computer Peripherals in the Category Table
Laptops in the Product Table
HP in the Optional Items Table, there can be many such options
HP Type A Parent in the Optional items Table
HP Type B Parent in the Optional items Table
HP Type B Child in the Optional items Table
HP Type C Super Parent in the Optional items Table
HP Type C Parent in the Optional items Table
HP Type C Child in the Optional items Table
Lenovo in the Optional Items Table in the Optional items Table
Sony in the Optional Items Table in the Optional items Table
Graphics Card in the Product Table
Mobiles in the Category Table
I have the following
models.py
class Product(models.Model):
productid = models.AutoField(primary_key=True)
productname = models.CharField(max_length=255, unique=True)
categoryid = models.ForeignKey(Categorytbl, db_column='CategoryID')
class Optionalitemstbl(models.Model):
optionid = models.AutoField(primary_key=True)
productid = models.ForeignKey(Product)
optionname = models.CharField(max_length=255, unique=True)
optionparentid = models.ForeignKey("self", related_name='+', blank=True, null=True)
def clean(self, *args, **kwargs):
if self.optionparentid and self.productid:
if self.optionparentid.optionid == self.optionid:
from django.core.exceptions import ValidationError
raise ValidationError('Option cannot be an option of itself')
return
super(Optionalitemstbl, self).save(*args, **kwargs)
This enables me to create relationships as in the analogy above.
However the issue is, it also allows circular relationships. Say if a user has made the listing as in the analogy above in the admin site, it is possible for him to also list HP Type C Child as a parent of HP or any of its other parent nodes in the table.
Please suggest -
Is this the right approach for the analogy mentioned?
If it is, what modifications will prevent such circular relationships?
Thanks !

Related

count number of followers(users) and no of following(users) in django ORM

I am creating a tool where users can follow each other. The way I have Implemented this is by extending the user model in Django as people model.
here is the people Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,related_name='people')
Name = models.CharField(max_length=255,null=True)
following = models.ManyToManyField(to=User, related_name='following', blank=True)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
Here the poeple model is extended from user model and the relation is defined using oneToOneField.
Now the following column has many to many relation to the user model.
The Schema of the people_following table is that is has 3 columns
ID -> unique Identified (Primary Key)
People_id = user that has been followed.
User_id = user who is following(Logged in user)
suppose user with ID = 2 is logged in and wants to follow the User with ID = 7
then following will be the row in the table ->
ID people_id user_id
1 7 2
Now I would like to count the no of followers and the no of people following a particular user(Logged In user)
here is the Query ->
user_id = pk
person = People.objects.select_related('user').get(user_id=user_id)
context = {
'followers': person.following.filter(people_id=user_id).count(),
'following': person.following.filter(user_id = user_id).count(),
}
But this is giving me error ->
cannot resolve keyword -> people_id.
can anyone help me out with this.

Filtering down through multiple ForeignKey relations in django

I am trying to get down through multiple-foreign key relationship where each Hotel has many Rooms, each Room has many Rateplans, each Rateplan has many Prices.
It resembles Christmas tree if you think about it:
Hotel
v
Room
v
Rateplan
v
Prices
How can I execute query that will return hotels in certain hotel_city on certain price_date, certain price_price and certain price_availability? (just like Expedia or booking.com query)
For example:
Hotel.objects.filter(city='Beirut').filter(room__name=Room.objects.filter(rateplan__name=Rateplan.objects.filter(prices__availability=Prices.objects.filter(availability=1))))
I have looked into django complex queries documentation and annotate/aggregate but couldn't wrap my head around it.
My models below:
class Hotel(models.Model):
name = models.CharField(max_length=64)
city = models.CharField(max_length=64, default='Warsaw')
class Room(models.Model):
hotel_id = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name='room')
name = models.CharField(max_length=64, default='Double')
class Rateplan(models.Model):
room_id = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='rateplan')
name = models.CharField(max_length=64, default='Standard')
class Prices(models.Model):
rateplan_id = models.ForeignKey(Rateplan, on_delete=models.CASCADE, related_name='prices')
date = models.DateField()
price_1 = models.DecimalField(null=False, max_digits=7, decimal_places=2)
price_2 = models.DecimalField(null=False, max_digits=7, decimal_places=2)
availability = models.SmallIntegerField()```
You can use __ to filter the values you need across relationships
There are good examples in the documentation
Hotel.objects.filter(
city=your_city,
room__rateplan__prices__date=your_date,
room__rateplan__prices__price_1=your_price,
room__rateplan__prices__availability=your_availability,
).distinct()

How to fix ''Follow.s_id' is not a foreign key to 'Users'." in this model

I am new to Django framework, I am trying to build the following system which contains a user who follows multiple stocks and the stocks are followed by multiple people, I'm trying to create a composite key using an intermediate class, but I'm having this error.
class Stock(models.Model):
symbol = models.CharField(max_length=12, primary_key=True,default="")
name = models.CharField(max_length=64)
top_rank = models.IntegerField(null=True)
price = models.FloatField()
change = models.FloatField(null=True)
change_percent = models.FloatField()
market_cap = models.FloatField(null=True)
primary_exchange = models.CharField(null=True, max_length=32) # NASDAQ
followers = models.ManyToManyField('myapp.Users',through='Follow',through_fields=('u_id','s_id'))
class Users(models.Model):
user_id = models.IntegerField(primary_key=True,default="")
name = models.CharField(max_length=12)
class Follow(models.Model):
u_id=models.ForeignKey('Users',on_delete=models.CASCADE)
s_id=models.ForeignKey('Stock',on_delete=models.CASCADE)
myapp.Stock.followers: (fields.E339) 'Follow.s_id' is not a foreign key to 'Users'.
HINT: Did you mean one of the following foreign keys to 'Users': u_id?
myapp.Stock.followers: (fields.E339) 'Follow.u_id' is not a foreign key to 'Stock'.
HINT: Did you mean one of the following foreign keys to 'Stock': s_id?
The order of the through_fields [Django-doc] is incorrect. As specified in the documentation:
through_fields accepts a 2-tuple ('field1', 'field2'), where field1 is the name of the foreign key to the model the ManyToManyField is defined on (...), and field2 the name of the foreign key to the target model (...).
So that means the first item of the through_fields should be 's_id' here, since that refers to the Stock model, the model where you defined the ManyToManyField, and the second item should be 'u_id':
class Stock(models.Model):
# …
followers = models.ManyToManyField(
'myapp.Users',
through='Follow',
through_fields=('s_id','u_id')
)
That being said, you here do not need to define the through_fields here, since your Follow model contains exactly two ForeignKeys that point to different models. In fact you do not need to define a through=... model either, since it does not contain any extra fields.
Note that usually a ForeignKey does not contain an _id suffix, since Django will automatically add an extra field with the _id suffix that contains the primary key of the referenced value.
Therefore it might make more sense, to just define the models as:
class Stock(models.Model):
symbol = models.CharField(max_length=12, primary_key=True)
name = models.CharField(max_length=64)
top_rank = models.IntegerField(null=True)
price = models.FloatField()
change = models.FloatField(null=True)
change_percent = models.FloatField()
market_cap = models.FloatField(null=True)
primary_exchange = models.CharField(null=True, max_length=32) # NASDAQ
followers = models.ManyToManyField('myapp.User')
class User(models.Model):
user_id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=12)
Note that models usually have a singular name, so User, instead of Users.

how to reference to the django user model

hello i have a model named Assigned_problem in which a need to add two foreign keys of the model user in it. one foreign key represents the person who assigned the problem and the other foreign key represents the person to whom the problem is assigned. so in the course of updating the modifications done one the database structure i ave the following errors
mini_url.Assigned_problem.assigned_to: (fields.E305) Reverse query name for 'Assigned_problem.assigned_to' clashes with reverse query name for 'Assigned_problem .assigned_by'. HINT: Add or change a related_name argument to the definition for 'Assigned_problem.assigned_to' or 'Assigned_problem.assigned_by'.
THIS IS MY MODEL STRUCTURE
class Assigned_problem(models.Model):
assignation_status = models.IntegerField()
assigned_date = models.DateTimeField(auto_now_add=True, auto_now=False,
verbose_name="Assigned Date")
assigned_to = models.ForeignKey(User)
assigned_by = models.OneToOneField(User)
problem = models.OneToOneField('Problem')
def __str__(self):
return "{0}".'format'(self.problem.problem_content)
With
assigned_to = models.ForeignKey(User)
assigned_by = models.OneToOneField(User)
you declared two ForeignKeys to the model User. They're not distinguishable by their relation to User itself. Try to add a related_name attr for each of your foreign keys to User.
assigned_to = models.ForeignKey(User, related_name="User assigned to")
assigned_by = models.OneToOneField(User, related_name="User assigned by")
See the django docs

Backbone: adding models to a collection

On the one hand, i have three CollectionsView (three types of models fetched from the server), on the other hand i have a quarter CollectionView that works like a shopping cart. This stores items from the other three Collections associated with the views (Collections Views).
The problem is when i add a item with the same id this is edited, not added to the Shopping cart CollectionView.
Example:
function addToCart(model){
ShoppingCartCollectionView.collection.add(model);
}
From the others collections:
// From one CollectionView
addToCart(this.model);
// From another CollectionView
addToCart(this.model);
This Collections have the same id because they are stored in diferent databases on the server.
This is my model (Python ORM)
PRODUCT_TYPE = (
('EM', 'Empanada'),
('BE', 'Bebida'),
('OF', 'Oferta'),
)
# Create your models here.
class Producto(models.Model):
nombre = models.CharField(max_length=50)
precio_unidad = models.DecimalField(max_digits=8, decimal_places=2)
descripcion = models.TextField()
stock = models.IntegerField()
status = models.BooleanField(default=True)
imagen = models.ImageField(upload_to=upload_to)
fecha_publicacion = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class Empanada(Producto):
precio_docena = models.DecimalField(max_digits=8, decimal_places=2)
product_type = models.CharField(max_length=2, choices=PRODUCT_TYPE, default='EM', editable=False)
def __unicode__(self):
return self.nombre
class Bebida(Producto):
product_type = models.CharField(max_length=2, choices=PRODUCT_TYPE, default='BE', editable=False)
def __unicode__(self):
return self.nombre
class Oferta(Producto):
product_type = models.CharField(max_length=2, choices=PRODUCT_TYPE, default='OF', editable=False)
def __unicode__(self):
return self.nombre
class Venta(models.Model):
pedido = models.TextField()
total = models.DecimalField(max_digits=8, decimal_places=2)
status = models.BooleanField(default=True)
fecha_publicacion = models.DateTimeField(auto_now_add=True)
How to solve this?
THANKS !!!
#KimGysen is right about looking into restructuring your products tables. Having different products with the same id is going to cause you problems in the long run. Here's a database schema that may work for you.
Using foreign key tables
First you'd have a product name table where you'd list the name of your different products and assign each product type a primary key (ID). Then, group the different attributes of your product and make a separate table for each group. In the table you'd refer to your original product types by their ID (this is your foreign key). Here's a simple diagram:
/*Name Table Prod Type 1
------------------------------- ---------------------------------
| ID | Product Name | Prod Type | ProdId | attr1 | ... | attrN |
------------------------------- ---------------------------------
| 1 | Product 1 | 1 | | 1 | val1 | ... | valN |
------------------------------- ---------------------------------*/
Work with or around collection.set
Your other option is to override the collection.set method in Backbone, which is responsible for identifying whether there are duplicates in your set.
Cheating collection.set
If you're having problems because your adding two different types of products with the same id you can cheat collection.set by making sure that their id attribute is called something other than id (this is what set uses to evaluate whether you have to identical models in your collection, unless you tell it to check a different property by setting the idAttribute property in your model definition). Then collection.set will not know how to match incoming models.
Overriding collection.set
If you're having trouble because collection.set is not storing a model that is already in your collection, then you will have to override collection.set. Let me know if this is the fix you're looking for and I'll post that answer here.
Create a new ShoppingCart Model
A third possibility is to have a ShoppingCart model that handles the addition and removal of models. This is a more complicated solution. If you provide more details about how your cart is being used I can drop a few ideas on how to get your started.

Resources