For more than a year, I construct many of my query using a Django Model where I have simple relation between none abstract model objects and everything was working perfectly :
class Taxon(models.Model):
parent = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True, related_name='children')
rank = models.CharField(max_length=200, unique=False, default="NA")
name = models.CharField(max_length=200, unique=False, default="NA")
class Sequence(models.Model):
taxon = models.ForeignKey(Taxon, null=True, blank=True, on_delete=models.CASCADE)
amplicon = models.CharField(max_length=1000, unique=False)
sequence = models.CharField(max_length=1000, unique=False)
score = models.FloatField()
Exemple of queryset using my Model :
taxon.sequence_set.filter(stuff_filtering)
But recently I had to apply some modifications on my database and my Sequence objects are now derivated from an Abstract class called Observation, becoming this
class Observation(models.Model):
taxon = models.ForeignKey(Taxon, null=True, blank=True, on_delete=models.CASCADE)
class Meta:
abstract = True
class Sequence(Observation):
amplicon = models.CharField(max_length=1000, unique=False)
sequence = models.CharField(max_length=1000, unique=False)
score = models.FloatField()
def __str__(self):
return str((self.amplicon, self.sequence, self.score, self.taxon))
I didn't changed anything in my queryset because django documentation about abstract class (https://docs.djangoproject.com/en/3.2/topics/db/models/) say you can still use your chlid_set in a query. However i'm facing this error and I couldn't understand why.
AttributeError: 'QuerySet' object has no attribute 'sequence_set'
Knowing that in case of Abstract base classes, a table should be created in db for each child with parent attribute... So i have Sequence object with linked Taxon object
Apparently the solution to this problem if to retrieve the Taxon object with a get and not a filter (event if only one object is returned).
taxon = Taxon.objects.filter(...)
returning just one value became
taxon = Taxon.objects.get(...)
It's seems a pretty mysterious for me, as I still don't understand why it has worked perfectly with my previous model
Related
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).
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
Is there a way to refer to specific object of Model? Suppose I have some models like below:
# models.py
class VehicleCategoryCode(models.Model):
category = models.CharField(max_length=5)
name = models.CharField(max_length=20)
class Code(models.Model):
category = models.ForeignKey(VehicleCategoryCode, on_delete=models.CASCADE)
index = models.CharField(max_length=4, blank=True)
label = models.CharField(max_length=50)
order = models.CharField(max_length=20, blank=True)
is_active = models.BooleanField(default=True)
# pay attention to the Model
class Vehicle(models.Model):
label = models.CharField(max_length=80)
model = models.CharField(max_length=30)
Currently Vehicle is not linked to any model.
Now Code model is ForeignKey to VehicleCategoryCode, which has two objects. In the VehicleCategoryCode the first object label (for convenience sake) will be referenced by Vehicle.label, and the second object model (once again for convenience) will be referenced by Vehicle.model. So each field in Vehicle can refer to the same model, but different objects.
So basically I'm wondering if something like the pseudo code below can be achieved anyhow.
class Vehicle(models.Model):
label = models.ForeignKey(VehicleCategoryCode__name='label', on_delete=models.CASCADE)
model = models.ForeignKey(VehicleCategoryCOde__name='model', on_delete=models.CASCADE)
Any suggestion or advice would be appreciated. Thank you.
You can make use of the limit_choices_to=… parameter [Django-doc]:
Vehicle(models.Model):
label = models.ForeignKey(
Code,
limit_choices_to={'category__name': 'label'},
on_delete=models.CASCADE
)
model = models.ForeignKey(
Code,
limit_choices_to={'category__name': 'model'},
on_delete=models.CASCADE
)
For ModelForms and in the ModelAdmin it will limit the choices, note however that tese are not enforced by the database.
I'm having a problem where if I delete an object, another object is being deleted seemingly wrongly.
models.py
class Document(models.model):
file = models.FileField(upload_to=document_path, null=True, max_length=256)
ri_ct = models.ForeignKey(
ContentType, null=True, editable=False, related_name='documents_related_item', on_delete=models.PROTECT
)
ri_id = models.PositiveIntegerField(null=True, editable=False, db_index=True)
related_item = GenericForeignKey('ri_ct', 'ri_id')
class Invoice(models.model):
documents = GenericRelation(
Document, related_query_name='invoices', content_type_field='ri_ct', object_id_field='ri_id'
)
class BalanceUpdate(models.model):
related_item_ct = models.ForeignKey(
ContentType,
limit_choices_to=Q(app_label='main', model__in=('proformainvoice', 'invoice')),
related_name='balance_updates',
null=True,
on_delete=models.PROTECT,
)
related_item_id = models.PositiveIntegerField(null=True, blank=True, db_index=True)
related_item = GenericForeignKey(ct_field='related_item_ct', fk_field='related_item_id')
Now, if I do
Invoice.objects.filter(query).delete()
I'm getting a BalanceUpdate, which is related to Invoice, also deleted.
After a fair amount of debugging I've found that when deleting the Invoice, the document is being deleted (correctly due to the defined GenericRelation).
If we look at Collector.collect we have a recursive function which collects the objects to be deleted.
If I insert a print here, when the model is Document, sub_objs contains the BalanceUpdate object. How can this be the case? The Document obj surely should have sub_objs containing a BalanceUpdate, they are seemingly not linked?
Cheers in advance.
Take the following as an example:
class Manufacturer(models.Model):
name = models.CharField(max_length=200, blank=False)
slug = models.SlugField(max_length=200, blank=False, unique=True)
class Category(models.Model):
name = models.CharField(max_length=200, blank=False)
slug = models.SlugField(max_length=200, blank=False, unique=True)
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products')
manufacturer = models.ForeignKey(Manufacturer, related_name='products')
name = models.CharField(max_length=50, blank=False)
slug = models.SlugField(max_length=200, blank=False, unique=True)
class CarMixin(models.Model):
color = models.CharField(max_length=50, blank=False)
num_wheels = models.IntegerField()
class CellPhoneMixin(models.Model):
screen_size = models.IntegerField()
class Car(Product, CarMixin):
pass
class Food(Product):
pass
class CellPhone(Product, CellPhoneMixin):
pass
what I am trying to do is create a 'base' class called Product and apply a variety of 'sub-product-types' using Model Inheritance.
The reason I am not using the Django's 'Abstract Model Inheritance' is because I actually want a table in my DB to hold all the products, so I can make a query like Product.objects.all() to get all the products, then type product.car to get all the field values for the related Car object.
However, the problem I am running into is that a product can have a relationship with any one of Car, Food or CellPhone. So, I can't do product.car if it has a relationship with Food. There is no way in knowing which 'relationship' a Product object has. Is it related to Car? Food? CellPhone?
How should I approach this? Is there a better database schema I should be using?