Should I use oneToMnay or ManyToMany in django - python

I am new in django and trying to create a website where I can search for vehicles and see what parts I have for this vehicle.
I have two databases, one with vehicles and one with parts:
class Vehicle(models.Model):
vehicle_id = models.BigIntegerField(primary_key=True)
vehicle = models.CharField(max_length=255)
def __str__(self):
return self.vehicle
class Part(models.Model):
part_id = models.BigIntegerField(primary_key=True, db_column='part_id')
part_name = models.CharField(max_length=255, db_index=True, null=True)
catalog_code = models.CharField(max_length=255, null=True)
price = models.CharField(max_length=255, default=None, null=True)
description = models.CharField(max_length=255, default=None, null=True)
vehicle_id = models.ForeignKey(Vehicle, on_delete=models.PROTECT, null=True)
def __str__(self):
return self.part_name
Now I using oneToMany, but can't figure out if it is correct and how can I see all parts for one vehicle

You implemented the relationship correctly. One to many is a way to go here.
You can make your life easier by defining related_name in the ForeighKey:
vehicle_id = models.ForeignKey(Vehicle, on_delete=models.PROTECT, null=True, related_name="parts")
and use the following constructs when referring to the vehicle parts:
myvehicle.parts.all()
myvehicle.parts.filter(part__part_id=1)
Side comment: I do not think that it was a good idea to define id fields explicitly. Django sets model id fields automatically (and defines them as primary keys).

Related

Solution to filter by Cumulative sum and error: Window is disallowed in the filter clause

This is follow-up to a question to:
Filter Queries which sum of their amount field are greater or lesser than a number
which is supposed to be solved. Answer suggests using Window function with filter but this results in a error:
django.db.utils.NotSupportedError: Window is disallowed in the filter clause.
Comment from #atabak hooshangi suggests removing the Window function, but query doesn't work in intended way after that. Any ideas to solve this problem?
let's say we have these 2 models:
class Developer(models.Model):
first_name = models.CharField(max_length=40, null=False, blank=False,
unique=True)
last_name = models.CharField(max_length=40, null=False, blank=False,
unique=True)
profession = models.CharField(max_length=100, null=False)
cv = models.FileField(upload_to=upload_cv_location, null=True, blank=True)
description = models.TextField()
img = models.ImageField(upload_to=upload_location, null=True, blank=True)
class Meta:
verbose_name = 'Developer'
verbose_name_plural = 'Developers'
ordering = ('first_name',)
def __str__(self):
return f'{self.first_name} {self.last_name}'
class Skill(models.Model):
developer = models.ForeignKey(to=Developer, on_delete=models.CASCADE)
category = models.ForeignKey(to=SkillCategory, on_delete=models.SET_NULL,
null=True)
name = models.CharField(max_length=50, null=False)
priority = models.PositiveIntegerField()
class Meta:
ordering = ('-priority',)
def __str__(self):
return f'{self.name} skill of {self.developer}'
As you can see , we have a developer model which has relationship with skill. Each developer can have multiple skills.
now consider we want to get the developers whos sum of their priorities are greater than a number.
The orm query should work this way :
from django.db.models import Sum
developers = Developer.objects.annotate(tot=Sum('skill__priority')).filter(tot__gt=250).all()
The output will be the developers who has greater than 250 priority_sum .
You can filter tot which is an annotated variable in any way you want.
like .filter(tot__lte)
or
.filter(tot__lt)
I hope this is what you were looking for.

Django Model Instance as Template for Another Model that is populated by Models

I'm trying to create a workout tracking application where a user can:
Create an instance of an ExerciseTemplate model from a list of available Exercise models. I've created these as models so that the user can create custom Exercises in the future. There is also an ExerciseInstance which is to be used to track and modify the ExerciseTemplate created by the user, or someone else. I'm stripping the models of several unimportant fields for simplicity, but each contains the following:
class Exercise(models.Model):
# Basic Variables
name = models.CharField(max_length=128)
description = models.TextField(null=True, blank=True)
def __str__(self):
return self.name
class ExerciseTemplate(models.Model):
# Foreign Models
workout = models.ForeignKey(
'Workout',
on_delete=models.SET_NULL,
null=True,
blank=True
)
exercise = models.ForeignKey(
Exercise,
on_delete=models.SET_NULL,
null=True,
blank=True
)
recommended_sets = models.PositiveIntegerField(null=True, blank=True)
class ExerciseInstance(models.Model):
""" Foreign Models """
exercise_template = models.ForeignKey(
ExerciseTemplate,
on_delete=models.SET_NULL,
null=True,
blank=True
)
workout = models.ForeignKey(
'Workout',
on_delete=models.SET_NULL,
null=True,
blank=True
)
""" Fields """
weight = models.PositiveIntegerField(null=True, blank=True)
reps = models.PositiveIntegerField(null=True, blank=True)
Create a WorkoutInstance from a WorkoutTemplate. The WorkoutTemplate is made up of ExerciseTemplates. But the WorkoutInstance should be able to take the WorkoutTemplate and populate it with ExerciseInstances based on the ExerciseTemplates in the WorkoutTemplate. Here are the models that I have so far:
class WorkoutTemplate(models.Model):
name = models.CharField(max_length=128)
description = models.TextField(null=True, blank=True)
date = models.DateTimeField(null=True, blank=True)
#category...
exercises = models.ManyToManyField(
Exercise,
through=ExerciseTemplate
)
def __str__(self):
return self.name
class WorkoutInstance(models.Model):
# Foreign Models
workout_template = models.ForeignKey(
'WorkoutTemplate',
on_delete=models.SET_NULL,
null=True,
blank=True
)
But this is where I get stuck. I'm not sure how to proceed. My intuition is one of the following:
I need to create a more simple architecture to do this. I'll take any suggestions.
I need to create a method within the model that solves this issue. If this is the case, I'm not sure what this would actually look like.
When you create a new WorkoutInstance object which references a given WorkoutTemplate object you get all its related ExerciseTemplate objects.
Then you just create a new object (row) for each ExerciseInstance in another model (table)
If you link your ExerciseInstance to WorkoutInstance via 'workout' you could do something like:
wt = WorkoutTemplate.get(id=1)
wi = WorkoutInstance.create(workout_template=wt)
for e in wt.exercisetemplate_set.all:
ExerciseInstance.create(exercise_template=e, workout=wi)
You can implent this in the method that creates the new WorkoutInstance or take a look at signals
https://docs.djangoproject.com/en/4.0/topics/db/optimization/#create-in-bulk

Django multiple foreign key to a same table

I need to log the transaction of the item movement in a warehouse. I've 3 tables as shown in the below image. However Django response error:
ERRORS:
chemstore.ItemTransaction: (models.E007) Field 'outbin' has column name 'bin_code_id' that is used by another field.
which is complaining of multiple uses of the same foreign key. Is my table design problem? or is it not allowed under Django? How can I achieve this under Django? thankyou
DB design
[Models]
class BinLocation(models.Model):
bin_code = models.CharField(max_length=10, unique=True)
desc = models.CharField(max_length=50)
def __str__(self):
return f"{self.bin_code}"
class Meta:
indexes = [models.Index(fields=['bin_code'])]
class ItemMaster(models.Model):
item_code = models.CharField(max_length=20, unique=True)
desc = models.CharField(max_length=50)
long_desc = models.CharField(max_length=150, blank=True)
helper_qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
def __str__(self):
return f"{self.item_code}"
class Meta:
verbose_name = "Item"
verbose_name_plural = "Items"
indexes = [models.Index(fields=['item_code'])]
class ItemTransaction(models.Model):
trace_code = models.CharField(max_length=20, unique=False)
item_code = models.ForeignKey(
ItemMaster, related_name='trans', on_delete=models.CASCADE, null=False)
datetime = models.DateTimeField(auto_now=False, auto_now_add=False)
qty = models.DecimalField(max_digits=10, decimal_places=4)
unit = models.CharField(max_length=10, blank=False)
action = models.CharField(
max_length=1, choices=ACTION, blank=False, null=False)
in_bin = models.ForeignKey(
BinLocation, related_name='in_logs', db_column='bin_code_id', on_delete=models.CASCADE, null=False)
out_bin = models.ForeignKey(
BinLocation, related_name='out_logs', db_column='bin_code_id', on_delete=models.CASCADE, null=False)
remarks = models.TextField(blank=True)
def __str__(self):
return f"{self.trace_code} {self.datetime} {self.item_code} {dict(ACTION)[self.action]} {self.qty} {self.unit} {self.in_bin} {self.out_bin}"
you have same db_column in two fields so change it
in_bin = models.ForeignKey(
BinLocation, related_name='in_logs', db_column='bin_code_id', on_delete=models.CASCADE, null=False)
out_bin = models.ForeignKey(
BinLocation, related_name='out_logs', db_column='other_bin_code', on_delete=models.CASCADE, null=False) /*change db_column whatever you want but it should be unique*/
If are linked to the same model name, You should use different related_name for each foreign_key filed . here is the exemple :
address1 = models.ForeignKey(Address, verbose_name=_("Address1"),related_name="Address1", null=True, blank=True,on_delete=models.SET_NULL)
address2 = models.ForeignKey(Address, verbose_name=_("Address2"),related_name="Address2", null=True, blank=True,on_delete=models.SET_NULL)
thank you for everyone helped. According to Aleksei and Tabaane, it is my DB design issue (broken the RDBMS rule) rather than Django issue. I searched online and find something similar: ONE-TO-MANY DB design pattern
In my case, I should store in bin and out bin as separated transaction instead of both in and out in a single transaction. This is my solution. thankyou.
p.s. alternative solution: I keep in bin and out bin as single transaction, but I don't use foreign key for bins, query both in bin and out bin for the bin selection by client application.

django model field depend on the value of another field

The use case of my application is I will have various fields to fill and among them one is Industry field and another is Segment Field for brand. The industry field is like category that brand falls into. So, if i choose the industry as Health Care for XYZ brand then the segment field should show the items like 'Ayurveda', 'Dental Clinics' (all health care related items). Basically, its like sub-category.
Here is a sample model
class Industry(models.Model):
name = models.CharField(max_length=150, blank=True, null=True)
class Meta:
verbose_name = 'Industry'
verbose_name_plural = 'Industries'
def __str__(self):
return self.name
class Segment(models.Model):
industry = models.ForeignKey(Industry, related_name='segment', on_delete=models.CASCADE)
name = models.CharField(max_length=150, blank=True, null=True)
class Meta:
verbose_name = 'Segment'
verbose_name_plural = 'Segments'
def __str__(self):
return f'{self.industry.name} - {self.name}'
class BusinessModel(models):
industry = models.ForeignKey(Industry, blank=False, null=False, related_name='industry', on_delete=models.CASCADE)
# segements = models.ForeignKey()
total_investment = models.CharField() # will be choice field
This is a simple model and I have not created Segment model as I am not sure how to approach to this problem. I am just curios to know, if for such case, do i have to something special in models.py or in the view side. Such type of things get arise during development phase, thus, I want to be clear on problem solving pattern in django.
UPDATE
https://www.franchisebazar.com/franchisor-registration here if you choose industry inside Business model section, the segment will be updated accordingly.
You can have a 3 model design like
class Industry(models.Model):
name = models.CharField(max_length=150, blank=True, null=True)
class Segment(models.Model):
name = models.CharField(max_length=150, blank=True, null=True)
class Mapping(models.Model):
industry = models.ForeignKey(Industry)
segment = models.ForeignKey(Segment)
You need to define relations between your models. You can find documentation about ManyToMany relation here which is suitable in your case.
you can use ChainedForeginKey.. Check the below links
customizing admin of django to have dependent select fields
https://django-smart-selects.readthedocs.io/en/latest/installation.html

How to get count items in foreign key Django?

I have two classes of models and I need to get the number of products from a single vendor
class Vendor(models.Model):
name = models.CharField(max_length=50, unique=True)
seo_name = models.SlugField()
product_count = models.IntegerField(default=0)
class Product(models.Model):
vendor = models.ForeignKey(Vendor, unique=False, blank=True, default=None, null=True, on_delete=models.SET_NULL)
How to calculate the count of products in the Vendor ?
Take a look on Django recipe: Add an auto-count field to your model
tutorial. It totally covers your question.
Good Luck !

Categories

Resources