I'm currently trying to implement an API in Django Rest for a class project that's supposed to store data in a secure way.
I have two different models:
class Driver(models.Model):
name = models.CharField(max_length=100, blank=False, null=False)
and
import Driver
class Car(models.Model):
name = models.CharField(max_length=100, blank=False, null=False)
driver = models.ForeignKey(Driver, on_delete=models.CASCADE)
Currently, there's a mapping between cars and their respective drivers.
I'd like to map a car not to it's driver, but to the result of a hash function applied to it's driver name. Something like:
import Driver
import hashlib
class Car(models.Model):
name = models.CharField(max_length=100, blank=False, null=False)
driver = hashlib.md5(models.ForeignKey(Driver, on_delete=models.CASCADE).name).hexdigest()
I know what I wrote above is probably heretical in Django, it is just to convey the idea of what I want to do!
I thought about overriding the Car model's init, save, create functions in order to do this, but have strictly no idea what is the good option.
At the end of the process I'd like that there's no mapping between the Car and it's Driver, but a Driver's car could be found using the hash of his name.
Let me know if this is unclear or if you need more precision!
Any help would be appreciated,
Thanks!
You want to remove the explicit link from Car to Driver so you should not use a ForeignKey. Note the disadvantage is that you can't use a database JOIN to retrieve the car for a driver but will have to perform an extra query.
Create methods on your Car and Driver models to assign a driver and to retrieve the car:
class Car(models.Model):
...
driver = models.CharField(max_length=255)
def assign_driver(self, driver):
self.driver = hashlib.md5(driver.name).hexdigest()
class Driver(models.Model):
#property
def car(self):
try:
return Car.objects.get(driver=hashlib.md5(self.name).hexdigest())
except Car.DoesNotExist:
return None
This way, you can do my_driver.car to fetch the car for this driver of some_car.assign_driver(my_driver); some_car.save() to assign and save a driver.
Related
I have been trying to figure out the best way (or correct) way to set up models for our PIM/PriceModel app in Django.
Example models (stripped):
class ProductItem(models.Model):
"""
An actual item/product, what it all revolves around.
"""
part_number = models.CharField(unique=True, max_length=50, help_text='')
internal_part_number = models.CharField(primary_key=True, max_length=50, help_text='') # prefilled by partnumber
type = models.ForeignKey('Type', null=True, on_delete=models.SET_NULL)
attributes = JSONField() # Or another dynamic field
# and more ....
class Type(models.Model):
"""
Product type i.e. camera-dome, camera-bullet, pir, etc.
"""
pass
class Segment(models.Model):
"""
A segment of the company like Industry, Retail, Guarding etc.
"""
pass
class ProductCategory(models.Model):
"""
Supposedly a child category of TopCategory.
"""
pass
class InstallPrice(models.Model):
"""
Product item installation prices based on Type, Product Category and Segment.
"""
install_price = models.DecimalField(max_digits=8, decimal_places=2, help_text='')
type = models.ForeignKey('Type', null=True, on_delete=models.SET_NULL)
product_category = models.ForeignKey('ProductCategory', null=True, on_delete=models.SET_NULL)
segment = models.ForeignKey('Segment', null=True, on_delete=models.SET_NULL)
Take a look at "attributes = HStoreField(db_index=True)" in the ProductItem model.
The main thing i need to store in a product item is attributes like how many inputs/outputs/connection-options does it have. I need to store this for testing products against each other further down the line in the price-model app. This to make sure you have the right amount of products with matching attributes like inputs or outputs. I also need the User/Admin to be able to add this attributes dynamically so the app becomes self sustainable and not requires a migration id there is a new attribute I dont yet know about.
As I could not figure out a reasonable model configuration I ended up looking at postgres specific fields. This is not a must!
ideally when selecting type in the admin section i would like a "preset" of attributes to be presented based on the type.
Attributes could be:
inputs # number
outputs # number
channels # number
analysis # Boolean
Is this achievable? Any suggestions are welcome as I have limited Data Base experience. I need help figuring out the models.
I have object CarMaker:
class CarMaker(models.Model):
name = models.CharField(max_length=100)
And object CarModel stored in variable car_inst:
class CarModel(models.Model):
maker = models.ForeignKey(CarMaker, on_delete=models.CASCADE)
name = models.CharField(max_length=50, null=False, blank=False)
serial_number = models.CharField(max_length=50)
car_inst = CarModel.objects.get(id=foo)
I need to get the CarMaker that "owns" it.
I tried with:
maker = CarMaker.objects.get(id__in=car_inst.id)
This doesn't work. I've seen examples online of using backwards relations along the lines of:
maker = carmaker.carmodel_set.all()
But that didn't work either. What am I doing wrong here?
To get maker of car_inst you can just use car_inst.maker.
Reverse relations using in case you need to get list of cars related with specific maker maker.carmodel_set.all() this will give you all car models of the selected maker.
Let's take it step by step:
Get the CarModel object for which you want the CarMaker for :
car_model = CarModel.objects.get(id=foo)
Now, let us get the CarMaker associated with this object:
car_maker = car_model.maker
I'll make a quick resume so you can understand better the structure:
The Cars can be driven by different drivers and these drivers can get trophies. Trophies must be associated to the drivers and to the car they used.
class CarDriver(models.Model):
driver = models.ForeignKey('Driver', null=False)
car = models.ForeignKey('Car', null=False)
trophies = models.ManyToManyField('Trophy', blank=True)
class Driver(models.Model):
name = models.CharField(max_length=255)
class Car(models.Model):
name = models.CharField(max_length=255)
drivers = models.ManyToManyField(Driver, blank=True, through=CarDriver)
class Trophy(models.Model):
position = models.IntegerField(default=1)
I want to display the model Car in Django Admin but using a list of checkboxes to select the drivers, so the driver selection will be way faster than using inlines:
class CardDriverInline(admin.TabularInline):
model = CarDriver
class CarAdmin(admin.ModelAdmin):
inlines = [
CardDriverInline,
]
admin.site.register(Car, CarAdmin)
Is there a way to use checkboxes for multiple driver selection?
According to the Django docs, when you use a through argument to a ManyToManyField, the admin will not display a widget by default.
So, in this case you must use inlines, unfortunately.
However, if you don't use a through argument, you can simply have a ModelAdmin like this:
class CarAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {'widget': CheckboxSelectMultiple},
}
This way you have the checkboxes, but you lose the trophies reference.
I know, it isn't a fair world. I thought it would exist another way, but the Django docs is clear about why you have to use inlines with the through argument.
Since Django is mapping each model to a table. I am not able to create packages in my code. Where I can wrap sections of the class to make it more logical and increase the coupling.
For example
class Employee(models.Model):
#personal information
first_name = models.CharField(max_length=20)
middle_initial = models.CharField(max_length=1)
last_name = models.CharField(max_length=20)
dob = models.DateField()
#job contract information
full_time = models.BooleanField()
hours_per_day = models.PositiveSmallIntegerField()
#.. and more
What I am trying to do is this
employee.job.is_full_time
employee.job.get_hours_per_day
# and more
However this means that I have to create a new model and connect it with the employee model using OneToOneField. I don't want to do that .. joins in the database are expensive. Is there anyway to create something like this ?
class Employee(models.Model):
class PersonalInformation:
first_name = models.CharField(max_length=20)
middle_initial = models.CharField(max_length=1)
last_name = models.CharField(max_length=20)
dob = models.DateField()
class Job:
full_time = models.BooleanField()
hours_per_day = models.PositiveSmallIntegerField()
#.. and more
The main key to the answer is to create a model that contain multiple classes which are going to be mapped to one table in the database.
There is no way to do that with just Django. Django models represent flat, relational databases. Extending the model framework to provide functionality beyond what its backend is capable of is unnecessary, and therefore not implemented in the default framework.
There are third-party packages that provide what you want, but as far as I know these packages use database backends that are capable of using such data structures.
Personally I would go with your first example, a flat, single model that represents all my Employee data. Prevent any disambiguity in your field names, and there will be no cost for using a flat model over a nested model.
And remember: premature optimization is a lot more expensive than an join statement.
I am new to Django and databases and after reading the Django documentation on models I have the following question:
Let's say I have 3 models: VehicleName, CarManufacturer and TruckManufacturer. I am trying to create a database relationship where CarMaunfacturer has many VehicleNames and also TruckManufacturer has many VehicleNames. What is the relationship here and how to define it in Django? Is it as simple as define a models.ForeignKey(VehicleName) in both CarManufacturer and TruckManufacturer?
Thanks.
from django.db import models
class CarManufacturer(models.Model):
vehicle_name = models.ForeignKey(VehicleName) # IS THIS CORRECT???
# ...
pass
class TruckManufacturer(models.Model):
vehicle_name = models.ForeignKey(VehicleName) # IS THIS CORRECT???
# ...
pass
class VehicleName(models.Model):
# ...
To do exactly what you're describing:
I am trying to create a database relationship where CarMaunfacturer has many VehicleNames and also TruckManufacturer has many VehicleNames
You'd create a nullable foreign key on VehicleName to both of your Manufacturer models:
class CarManufacturer(models.Model):
# field definitions here
class TruckManufacturer(models.Model):
# field definitions here
class VehicleName(models.Model):
car_manufacturer = models.ForeignKey(CarManufacturer, blank=True, null=True)
truck_manufacturer = models.ForeignKey(TruckManufacturer, blank=True, null=True)
Then, instances of CarManufacturer or TruckManufacturer can get the names via the vehiclename_set attribute.
For a more advanced design, I would probably try to abstract the shared manufacturer behavior into a single model, then use multi-table inheritance:
class Manufacturer(models.Model):
# shared car and truck manufacturer fields go here
class CarManufacturer(Manufacturer):
# car manufacturer specific fields go here
class TruckManufacturer(Manufacturer):
# truck manufacturer specific fields go here
class VehicleName(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
See the multi-table inheritance docs for full details.
I do not think you are understanding the manufacturer to vehicle relationship property. What I think you are trying to show is that a certain Vehicle belongs to a certain manufacturer.
This type of relationship would actually be defined in the Vehicle class, as a foreign key, called manufacturer, in the Vehicle class.
In the case you are defining many vehicles under a manufacturer, you just need to rename the property to car_model or something of the like and you should be fine.
I think you have the understanding mapped out well enough. Just remember that foreign keys are only a property of one table, and say nothing about the other table itself until the relationship is established there also.
If you're working with a larger relationship, with multiple objects, you should look into using the Many-to-many field described in the django documentation.
They have an example that shows how an Articles have many Publications:
class Publication(models.Model):
title = models.CharField(max_length=30)
# On Python 3: def __str__(self):
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
# On Python 3: def __str__(self):
def __unicode__(self):
return self.headline
class Meta:
ordering = ('headline',)