I have the following two classes defined in models.py
class Part(models.Model):
name = models.CharField(max_length=32)
value = models.CharField(max_length=32)
class Car(models.Model):
name = models.CharField(max_length=32)
parts = models.ManyToManyField(Part)
So my model allows for multiple parts, but I want the part names to be unique. For example, only one part with name "engine" should be allowed for a given car. How do I enforce this uniqueness?
Things I have looked into:
class save()
Overriding the default save() for Car doesn't help because parts isn't updated until save is hit.
class save_model()
This will not work because it always saves.
So what are my options for enforcing uniqueness of part names?
UPDATED:
Although I want only one part with name engine to be associated with a car, I still want the ability to define multiple parts with name engine, of course with different values.
So a car with can have a part (part.name=Engine and part.value=V6) and another car can have a part (part.name=Engine and part.value=V4, but a car can't have two parts that have part.name == engine.
EDIT:
class Part(models.Model):
name = models.CharField(max_length=32)
value = models.CharField(max_length=32)
class CarPart(models.Model):
car = models.ForeignKey(Car)
part_type = models.CharField(max_length=32, unique=true)
part = models.ForeignKey(Part)
class Car(models.Model):
name = models.CharField(max_length=32)
treat part_type as part type id (e.g. type='engine') for engines it will be unique
more about ForeignKey
Related
In Django, if I have something like this:
class Library(models.Model):
name = models.CharField(...)
address = models.CharField(...)
book_of_the_week = ?
class Book(models.Model):
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name="books")
name = models.CharField(...)
This gives me the ability to create multiple libraries, each with a large number of books.
For book_of_the_week, I want this to be a reference to a Book instance, so that in Django Admin, the field is represented as a dropdown that lets you select from the books in the current library, and in code, you can use .book_of_the_week to access a specific instance of Book.
Is this possible?
Sure, it's possible. But if you do this, you'll only ever be able to save the current book of the week. What happens if you want to show a library's book-of-the-week history? Seems like a likely scenario to me. Consider doing something like:
class Library(models.Model):
name = models.CharField(...)
address = models.CharField(...)
book_of_the_week = ?
class Book(models.Model):
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name="books")
name = models.CharField(...)
class BookOfTheWeek(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='book_of_the_week')
library = models.ForeignKey(Library, ...etc)
week_of = models.DateField()
In this manner every book of the week will be a discrete database record, and you'll be able to track a history of each library's book of the week over time.
However...
That said, if you do not need to do this and a single instance record is fine, you should be able to create a ForeignKey relation from Library to Book. However, you may run into some circular and/or hierarchical reference issues depending on how where your model classes are written. In the example you show above, you'd need to declare your ForeignKey model name as a string, like so:
book_of_the_week = models.ForeignKey('Book', on_delete ... etc)
instead of:
book_of_the_week = models.ForeignKey(Book, on_delete ... etc)
...otherwise Django will throw an error because the Book model class is referenced before it is defined. Making 'Book' a string will let Django parse the full models.py file, build the logic, and avoid the error.
Sidenote:
Depending on your specific case you may also consider a ForeignKey to self, like so:
class Book(models.Model):
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name="books")
name = models.CharField(...)
book_of_the_week = models.ForeignKey('self', on_delete=models.SET_NULL, ...etc)
This would allow any Book on the database table to reference another single Book instance.
I'm sure there are probably several ways to do what I am achieving, but have run into some problems. I have a "Member" model and I'm also trying to add a "Dependent" model that inherits some fields and data from the parent (Member) but also has some of the same fields, but their own data. What would be the best way to achieve this? ForeignKey, OneToOne, or ManyToMany, or is it even possible?
Example:
class Member(models.Model):
name = models.CharField(max_length=128)
address = models.CharField(max_length=128)
age = models.DateField()
class Dependent(models.Model):
name = models.CharField(max_length=128) (different name)
address = models.CharField(max_length=128) (same address as Member)
age = models.DateField() (different age)
Thank you for your help.
Since Dependent has the same fields as Member but has some extra fields, you can make both Dependent and Member inherit an abstract base class (thanks to #WillemVanOnsem for pointing it out) to avoid redefining the same fields, and since Member and Dependent have a parent-child relationship, you should add a foreign key to Member as an additional field in the Dependent model. You can also override the save method of Member to make it sync the addresses of its Dependent children when saved.
class Person(models.Model):
name = models.CharField(max_length=128)
address = models.CharField(max_length=128)
age = models.DateField()
class Meta:
abstract = True
class Member(Person):
def save(self):
super().save()
self.dependents.exclude(address=self.address).update(address=self.address)
class Dependent(Person):
parent = models.ForeignKey(Member, related_name='dependents')
extra_field = ...
Sorry if this is confusing, I'm still a bit green with Django. So basically I have two models and I want a selection from one to have all the choices from another model. So basically:
class Show(models.Model):
venue = models.CharField(max_length=100, choices = VENUE NAME)
class Venues(models.Model):
Name = models.CharField(max_length=100)
Essentially I want the venue to have a list of the venue names that were input into that model. Is this possible?
In your case you should use many-to-one ForeignKey
It give you access to Venues object from your Show object and it simple to add this to your model.
class Show(models.Model):
venue = models.ForeignKey('Venues', on_delete=models.CASCADE)
class Venues(models.Model):
name = models.CharField(max_length=100)
To get your choices you can use:
Venues.objects.all()
And then the only thing you need is add object or ID to your Show object and save.
Choices are good too but not in this case. For example when you need some const and give user choices like this:
class Show(models.Model):
VENUES_CHOICES = (
(RESTAURANT, 'restaurant'),
(PUB, 'pub'),
)
venues = models.IntegerField(choices=VENUES_CHOICES, default=RESTAURANT)
Its great to use it in order status in my opinion.
add a str def like this in the Venues model will do
def __str__ (self):
return self.name
I need to put two Foreign Keys in a model class from two different models. I would like to relate the third model class to the first and the second.
I've tried something like this:
class A (models.Model)
id_A = models.IntergerField (primary_key=True)
#...
class B (models.Model)
id_B = models.IntergerField (primary_key=True)
#...
class C (models.Model)
id_A = models.ForeignKey(A)
id_B = models.ForeignKey(B)
Reading the docs I understand that is not possible to have MultipleColumnPrimaryKeys... but I Didn't receive any error from django with this models.py
Is it possible? Is there a smarter way?
Thank you!
You are doing it well, if you were relating id_A and id_B to a same model, django would give you an error, in this case just put related_name attribute in the second field.
Django didn't pop up error because you were doing it right. It's totally reasonable that there are multiple foreign keys in one model, just like class C.
In class C, as long as id_A and id_B is the single column primary keys of their own model, it will perfectly work out.
"MultipleColumnPrimaryKeys" you mentioned is a different thing. It means that for a specific table in database, there are multiple columns together to be the table's primary key, which is not supported in Django.
You can use a many-to-many relationship that automatically creates that intermediate model for you:
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication, related_name='articles')
With this you can do both:
publication.articles.all() # Gives you the articles of the current publication instance
article.publications.all() # Gives you the publications of the current article instance
Check out docs for many to many
If you need to use any additional fields in that intermediate model, you can tell django which is the through model like this:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Check out docs for extra fields on many to many
Also, if you are going for a standard integer auto-increment primary key, django already generates one for you so you don't need to define id_A and id_B.
I want to make a hierarchy over a DB design as described in "Fundamentals of database systems" from Elmasri & Navathe.
This implies that when I have some info which is shared for many classes/tables, I can put it in a main parent table and use the main table id as foreign key in the child tables, kind of a weak entity.
I tried using abstract and multitable inheritance (this last one doesn't let me specify the OneToOneField, don't know where to find this at django docs).
My example is right down here (one table per class):
'''I would like this to be abstract, because I will never instantiate it,
but could be not if needed'''
class Person(models.Model):
personId = models.IntegerField(primary_key=True)
name = models.CharField(max_length=45)
surname = models.CharField(max_length=45, blank=True)
email = models.CharField(max_length=45, blank=True)
phone = models.CharField(max_length=15, blank=True)
class Meta:
managed = False
db_table = 'person'
class Alumn(Person):
# Maybe this one down should be OneToOne.
# alumnId == personId always true for the same real world guy
alumnId = models.ForeignKey('Person', db_column='alumnId', primary_key=True)
comments = models.CharField(max_length=255, blank=True)
class Meta:
managed = False
db_table = 'alumn'
# There are more child classes (Client, Professor, etc....)
# but for the example this is enough
My target is achieving to create an Alumn in DB just with two sentences like:
a = Alumn(personId=1,name='Joe', [...more params...] , alumnId=1, comments='Some comments' )
a.save()
and having these two lines insert two rows: one for Person and one for Alumn. The alumnId attribute in this snippet up here could be omitted, because it will always be the same as the personId (I told you, like a weak entity).
I'm quite a beginner at django but I have looked at the documentation and proved some things with abstract=True in Person and not having succeeded I guess now that I should mess with the init constructors for getting the superclass built and after that build the child class.
I don't know the right path to choose but definitely want not to alter the database design. Please help.
Thanks in advance.
You don't need to have ids in your models; Django handle it automatically. Also you're not supposed to use camel case. In other words: personId should be person_id and is not necessary anyway - just remove it.
In general I avoid non-abstract inheritance with an ORM.
I don't really understand what you want to achieve but I'd suggest 2 approaches (for Person, Alumni, Professor, etc.), depending on your needs:
1. Abstract inheritance:
class Person:
class Meta:
abstract = True
# here you put all the common columns
Then:
class Alumni(Person):
# the other columns - specific to alumn
etc.
By doing this you have one table per sub-type of Person: Alumn, Professor etc.
2. Use composition:
class Alumn:
person = models.ForeignKey(Person, null=True, related_name="alumni_at")
university = ...
class Professor:
person = models.ForeignKey(Person, null=True, related_name="professor_at")
university = ...
This way you can do:
bob = Person.objects.create(first_name="bob", ...)
Alumn.objects.create(person=bob, university="univ 1")
Professor.objects.create(person=bob, university="univ 2")
Alumn.objects.create(person=bob, university="univ 2")