Let's say I have 3 models in Django: Person, Workfield and SubWorkfield.
A person can have many workfield-s and many subWorkfield-s as well, but the subWorkfield-s must be related to their parent workfield-s ( which the person must be related to).
So how do I enforce that whenever a person is related to a subWorkfield then he must also be related to that subWorkfield's parent workfield?
Here's what I have so far, but I don't think it enforces the relationship:
class Person(models.Model):
name = models.CharField(max_length=200)
workfield = models.ManyToManyField(Workfield)
subworkfield = models.ManyToManyField(SubWorkfield)
class Workfield(models.Model):
name = models.CharField(max_length=200)
class SubWorkfield(models.Model):
name = models.CharField(max_length=200)
workfield = models.ForeignKey(Workfield)
I need to have the workfields and subWorkfield-s decoupled because a person can belong to a workfield without any subWorkfield-s.
There really isn't any good way to do what you want purely with the table structure itself. However, if you do the following:
class Person(models.Model):
name = models.CharField(max_length=200)
workfields = models.ManyToManyField(Workfield)
subworkfields = models.ManyToManyField(SubWorkfield)
def add_subworkfield(self, subworkfield):
if subworkfield.workfield not in self.workfields:
return False
else:
self.subworkfields.append(subworkfield)
class Workfield(models.Model):
name = models.CharField(max_length=200)
class SubWorkfield(models.Model):
name = models.CharField(max_length=200)
workfield = models.ForeignKey(Workfield)
And then you will just use the add_subworkfield method when adding subworkfields to Persons.
Alternatively, inside of the Person model you could override the save method:
class Person(models.Model):
...
def save(self, *args, **kwargs):
for subworkfield in self.subworkfields:
if subworkfield.workfield not in self.workfields:
return
super(Person, self).save(*args, **kwargs)
If it's a small app and it's just you, the first way should suffice. However, if you're working on something larger with multiple people, overriding save would be a safety incase someone doesn't use the add_subworkfield method.
Related
Suppose in a relational database schema we have a student, a subject and a teacher which connect to each other with a relation teaches. Also, the relation has an attribute time that stores the time of the lesson. This is the most complete yet simplified example I can think to describe my case. Now, the most pythonic and django-wise way I can think of trying to reach a correct solution is, after creating a model class for student, subject and teacher, to create a new class Teaches, which has the foreign keys for the three other classes; also it has the property date field for time. This class would look something like this:
class Teaches(models.Model):
teachers = models.ForeignKey(Teacher, on_delete_models.CASCADE)
subjects = models.ForeignKey(Subject, on_delete_models.CASCADE)
students = models.ForeignKey(Student, on_delete_models.CASCADE)
time = models.DateField
class Meta:
constraints = [
fields=['teachers', 'subjects', 'students']
name='teacher_subject_student_triplet'
]
I added the Meta class because this is what this answer recommends as the correct approach.
The problem is that that in the migrations file I can still see the id field. The only way I've seen there is to remove it is to set another field as Primary Key, but in my case I cannot do that, having more than one keys. Any suggestions?
=========== model.py =============
from django.db import models
class TeacherModel(models.Model):
teacher_code = models.CharField(max_length=255)
def __str__(self):
return self.teacher_code
class SubjectModel(models.Model):
subject_code = models.CharField(max_length=255)
def __str__(self):
return self.subject_code
class StudentModel(models.Model):
student_code = models.CharField(max_length=255)
def __str__(self):
return self.student_code
class Teaches(models.Model):
custom_primary_key = models.SlugField(primary_key=True,blank=True)
teacher = models.ForeignKey(TeacherModel, on_delete=models.CASCADE)
subject = models.ForeignKey(SubjectModel, on_delete=models.CASCADE)
student = models.ForeignKey(StudentModel, on_delete=models.CASCADE)
time = models.DateField
#property
def make_key(self):
new_key = str(self.teacher.teacher_code + self.subject.subject_code + self.student.student_code)
return new_key
def save(self, *args, **kwargs):
self.custom_primary_key = self.make_key
super(Teaches, self).save(*args, **kwargs)
========= Output ==============
You can remove autogenerated id by adding primary_key=True, see below code:
class Person(models.Model):
username = CharField(primary_key=True, max_length=100)
first_name = CharField(null=True, blank=True, max_length=100)
setting a field to primary_key=True automatically makes it unique and not null.
In settings.py:
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
Controls the automatic generation of primary keys of each model if defined in settings.
Read this article:
Set AutoField or BigAutoField on a per model basis
I am struggling to understand django models relationship.
I have this arborescence:
A train have cars, and those cars are divided into parts. Then those parts all contains different references.
Like, for exemple, all the trains have the 6 cars, and the cars 6 parts. Each part have x reference to be associated.
I would like to use all of them in a template later on, where the user can select the train, the car and the part he worked on, then generate a table from his selections with only the references associated to the parts he selected.
It should update the train and the car (I'm trying to update a stock of elements for a company)
I dont really understand which model field give to each of them. After checking the doc, Ive done something like this but i am not convinced:
class Train(Car):
train = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Car(Part):
car = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Part(Reference):
part = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Reference(models.Model):
reference = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
def __str__(self):
return self.reference
Can someone please help me understand this so I can do well ? Thanks!!
1-)if you add abstract = True in your Model Meta class, your class doesn't created on database as a table. If you store data for any class, you mustn't define abstract = True.
2-)For relations, you can use models.ForeignKey . If you add a class into brackets of another class, it names: inheritance.(You can think like parent-child relation). In database management, we can use foreignkey for one-to-many relationship.
3-)In Django ORM, id field automatically generated. So you don't need to define id field.
If I understand correctly, also you want to store parts of user's selected.
So, your model can be like that:
class Train(models.Model):
name = models.CharField(max_length=200) # I think you want to save name of train
class Car(models.Model):
train = models.ForeignKey(Train,on_delete=models.Cascade)
name = models.CharField(max_length=200)
class Part(models.Model):
car = models.ForeignKey(Car,on_delete=models.Cascade)
name = models.CharField(max_length=200)
class Reference(models.Model):
part = models.ForeignKey(Part,on_delete=models.Cascade)
name = models.CharField(max_length=200)
def __str__(self):
return self.reference
#addtional table for storing user's references
class UserReference(models.Model):
user = models.ForeignKey(User,on_delete=models.Cascade)
reference = models.ForeignKey(Reference,on_delete=models.Cascade)
name = models.CharField(max_length=200)
With this definitions, you can store user's definition on UserReference table. And with Django Orm, you can access train object from UserReferenceObject.
#user_reference: UserReference object like that result of UserReference.objects.first()
user_reference.reference.part.car.train.name
I am in the process of designing a couple of new models for my django app and this is what I need:
class Bookmaker(models.Model):
name = models.CharField(max_length=50)
accepted_countries = ?
restricted_countries = ?
class Country(models.Model):
name = models.CharField(max_length=50)
bookmakers = ?
So I need a model Bookmaker and a model Country and they need to be related, BUT every bookmaker should have a list of countries that are accepted and a list of countries that are excluded.
The question marks are both in the Country and in the Bookmaker models as I'm not sure which way the relation should go.
Not sure if I'm on the right path, but I'm thinking that I need a couple of many-to-many relationships.. And, which is the right way (if any) to use the same Country model (those will be different instances) in both accepted_countries and restricted_countries?
Thanks.
You should use two many to many relations with related_name to separate them:
class Bookmaker(models.Model):
name = models.CharField(max_length=50)
accepted_countries = models.ManyToManyField(Country, related_name="accepted_for")
restricted_countries = models.ManyToManyField(Country, related_name="restricted_for")
You can then use the reverse relation as:
bookmakers_for_which_county_is_accepted = Country.objects.values('accepted_for').distinct()
bookmakers_for_which_county_is_restricted = Country.objects.values('restricted_for').distinct()
docs
You need indeed some many to many:
class Bookmaker(models.Model):
name = models.CharField(max_length=50)
accepted_countries = models.ManyToMany('Country',related_name='accepted')
restricted_countries = models.ManyToMany('Country', related_name= 'restricted')
class Country(models.Model):
name = models.CharField(max_length=50)
bookmakers = models.ManyToMany(Bookmaker)
Then if you create a form to edit a bookmaker you will be abble to add the name, the accepted and restricted countries:
forms.py
class BookmakerForm(models.ModelForm):
class Meta:
model = Bookmaker
fields = ['name', 'accepted_countries', 'restricted_countries']
#for having a better default display you can change the widget:
self __init__(self, *args, **kwargs):
super(BookmakerForm, self).__init__(*args, **kwargs)
self.fields['accepted_countries'].widget = CheckboxSelectMultiple()
self.fields['restricted_countries'].widget = CheckboxSelectMultiple()
In the view by default if you just need to check if form.is_valid() and save. django modelform will manage the intermediary step for you.
The bookmakers field in Country allows you to retrieve all the bookmaker associated to a country without having to check in both accepted and restricted (it's more for convenience).
But you will need to add the bookmaker to that list on you view like:
class CreateBookmakerView(CreateView):
model = Bookmaker
form_class = BookmakerForm
success_url = reverse_lazy('your success url name here')
def form_valid(self,form):
bookmaker = form.save()
bookmaker.country_set.add(bookmaker)
bookmaker.save()
return HttpResponseRedirect(self.get_success_url())
Hi there pretty new to django but considering the below models, with their relationships, how do I create a read only field for the object that is a reference to a field in another class? I've looked for a while on stackoverflow, but not sure what kind of model reference that would be.
The basic logic for this being:
I have this server rack that sites on a floor in a server room, and I'm associating it to a rack position, and row to manage power consumption and other goodies. Just for my end-user's reference I want a read only field to show them what row this rack lives in, and its derived from the rack position. I'd been fiddling around with creating a method to look it up, but can't seem to figure out the syntax or find something related on the django admin pages.
Any ideas would be super appreciated, I really could use the help as I've been staring through docs forever, and can't seem to find a relevant model reference for this.
class rack(models.Model):
class Meta:
verbose_name = "Rack"
verbose_name_plural = "Racks"
def __unicode__(self):
return str(self.position)
def row(self, obj):
return self.position.row
position = models.OneToOneField("rackposition")
row = row(position.row.row)
asstag = models.CharField("Asset Tag", max_length=200, unique=True)
rackunits = models.IntegerField("Rack Units")
class rackposition(models.Model):
class Meta:
verbose_name = "Rack Position"
verbose_name_plural = "Rack Positions"
def __unicode__(self):
return str(self.position)
position = models.CharField("Position", max_length=35, primary_key=True)
row = models.ForeignKey("row")
class row(models.Model):
class Meta:
verbose_name = "Row"
verbose_name_plural = "Rows"
def __unicode__(self):
return str(self.row) + "." + str(self.suite)
row = models.CharField("Row ID", max_length=200, unique=True)
suite = models.ForeignKey(suite, blank=False)
power_budget = models.IntegerField("Power Budget")
power_volt = models.IntegerField("Power Voltage")
dual_bus = models.BooleanField("Dual Bus", default=False)
You don't need a method. Assuming you have a rack instance called my_rack, you can get its row with my_rack.position.row.
Note, you should really follow PEP8 and use CamelCase for your class names.
If you want to see it as a readonly field in the admin, you will need to define a method either on the model or on the ModelAdmin class. For example:
class RackAdmin(admin.ModelAdmin):
model = Rack
readonly_fields = ('row',)
def row(self, obj):
return obj.position.row
I see no difference in sub classing the models.manager object and overriding the get_query_set method or simply creating a new method in the sub class and using the method. For the reason being I have taken example from the django book;
class MaleManager(models.Manager):
def get_query_set(self):
return super(MaleManager, self).get_query_set().filter(sex='M')
class FemaleManager(models.Manager):
def get_query_set(self):
return super(FemaleManager, self).get_query_set().filter(sex='F')
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
people = models.Manager()
men = MaleManager()
women = FemaleManager()
With this I could use; Person.women.all() or Person.men.all() to fetch all the men or women model object. But, I guess the similar thing can be achieved without overriding the get_query_set method by simply doing;
class MaleManager(models.Manager):
def get_male(self):
return self.filter(sex='M')
class FemaleManager(models.Manager):
def get_female(self):
return return self.filter(sex='F')
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
people = models.Manager()
men = MaleManager()
women = FemaleManager()
Now, with this, I can fetch all those objects with a little technique like;
Person.objects.get_male() or Person.objects.get_female(). But, there's no any subtle difference between how I could fetch the objects yet there is difference in terms of readability and use in first case while the second one is much easier to understand and has lesser code.Do they make some significant difference in coding and patterns ? The other thing with the second one, what if I place both the methods inside a same class like;
class PeopleManager(models.Manager):
def get_male(self):
return self.filter(sex='M')
def get_female(self):
return return self.filter(sex='F')
Usually you don't want several managers for the model. It's better to extend default manager.
class PeopleManager(models.Manager):
def get_male(self):
return self.filter(sex='M')
def get_female(self):
return return self.filter(sex='F')
class Person(models.Model):
....
objects = PeopleManager()
Then you will be able to use Person.objects.get_male(), Person.objects.get_female() and built-in methods like Person.objects.order_by(). You can look at custom managers in django.contrib.auth.models for example.
get_query_set is good for inheritance. For example you can define
class SmithManager(PeopleManager):
def get_queryset(self):
return super(SmithManager, self).get_query_set().filter(last_name='Smith')
and all the methods of the manager will return only Smiths, (Person.objects.get_male() will return only males named Smith and so on). And you don't need to rewrite all the methods.