Looking for advice on setting up this model.
This job board app has Company, Location, and Job. They should have the following relationships:
A Company can have multiple locations
A Company can have multiple jobs
A Job can have only one Company
A Job can have multiple locations, BUT each Location must be valid for the job's Company
I'd like to create a model that reflects these relationships. I think something like this might work:
class Company(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
class Location(models.Model):
is_primary_location = models.BooleanField()
address = models.CharField(max_length=200)
company = models.ForeignKey(Company)
class Job(models.Model):
title = models.CharField(max_length=200)
company = models.ForeignKey(Company)
location = models.ForeignKey(Location)
But I would really like the "Job has Location(s) through Company" relationship to be enforced. The model doesn't enforce it; I think I'd have to filter the valid Locations when data is displayed, and I'd like to avoid that.
Thanks very much!
Take a look at ForeignKey.limit_choices_to.
This allows you to filter the available choices and is enforced in ModelForm. Since you already have the company foreign key in your Job model, you should be able to use that to filter the choices.
I ended up using https://github.com/digi604/django-smart-selects and wrote the model like this. I don't think limit_choices_to works in this case (according to other SO threads)
from smart_selects.db_fields import ChainedForeignKey
class Company(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
class Location(models.Model):
is_primary_location = models.BooleanField()
address = models.CharField(max_length=200)
company = models.ForeignKey(Company)
class Job(models.Model):
title = models.CharField(max_length=200)
company = models.ForeignKey(Company)
location = ChainedForeignKey(
Location,
chained_field="company",
chained_model_field="company",
show_all=False,
auto_choose=True
)
Related
I'm doing some querying currently and I was wondering if I would be able to query something from these 3 models where the return would give me all the projects the users are working on. I know about the basic filtering however thats not really enough in this case, how would one go about querying through 2 foreign keys.
class User(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField()
class ProjectUser(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE)
user = models.ForeignKey("User", on_delete=models.CASCADE)
is_lead = models.BooleanField(default=False)
class Meta:
unique_together = (("project", "user"),)
class Project(models.Model):
name = models.CharField(max_length=255)
client = models.CharField(max_length=255)
complete = models.BooleanField(default=False)
You can obtain the Projects a user is working on with:
Project.objects.filter(
projectuser__user=user
)
The double underscores are used to look "through" relations. Furthermore the default related_query_name=… parameter [Django-doc] is, if not specified, the name of the model in lowercase.
I have an problem where I can’t decide how to design the models for the following scenario
I want to create a companies table that will hold a list of companies. This table will have a comment field in it
I want that comment field to be able to hold multiple comments that are dated
A company can have multiple comments but a comment can only belong to only one company
Here the Comments table
class Comments(model.Models):
date = models.DateField(auto_now_add=True)
comment_text = models.TextField(required=True)
If I create the Companies table like this;
class Companies(models.Model):
name = models.CharField(max_length=30)
country = models.CharField(max_length=30)
comment = models.ForeignKey(Comments, on_delete=models.SET_NULL, null=True)
Then I can only attach one comment to one specific row of the Companies table
If I create the Companies table like this;
class Companies(models.Model):
name = models.CharField(max_length=30)
country = models.CharField(max_length=30)
comment = models.ManyToManyField(Comments)
Then a comment can belong to multiple companies which I don’t want.
In the Django documentation https://docs.djangoproject.com/en/2.0/topics/db/examples/ there is only one other options left which is the one-to-one mapping and this is clearly not what I want.
How can achieve what I want ?
You should do this.
class Company(models.Model):
name = models.CharField(max_length=30)
country = models.CharField(max_length=30)
class Comment(models.Model):
company = models.ForeignKey(Company, related_name='comments', on_delete=models.CASCADE)
date = models.DateField(auto_now_add=True)
comment_text = models.TextField()
When accessing comments of a certain company, It will be;
comments = company.comments.all()
Just put the ForeignKey on Comment, pointing to Company. This does exactly what you want.
I am struggling to understand how one-to-many and many-to-many relation works in Django model. My schema looks something like this so far, I am open for suggestions to make it better.
A many-to-many relation between users and team. Also, there will be schedules that belong to a particular user of a team.
This is how my model looks like so far,
class Team(models.Model):
tid = models.AutoField(primary_key=True)
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
class Schedule(models.Model):
sid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
class BelongsTo(models.Model):
bid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
schedule = models.ForeignKey(Schedule, on_delete=models.CASCADE)
Question: I want to get the information of each user, what are their schedules and which team each schedule belongs to. How would I to do it? I have tried BelongsTo.objects.select_related().all(), but it is not working for me.
Note: I am open for suggestions, if something is wrong with my schema or model or the approach, please let me know.
BelongsTo is seems like utility table.So
BelongsTo.objects.all().values('user', 'team__team_name', 'schedule')
Your schema looks almost right, but I would modify it a little bit. In particular, I will change how Schedule is implemented. Instead of having a sid in the User Belongs To join-table, I would include the user and team in the Schedule table as foreign keys.
This is how the Django models should then look like:
class User(models.Model):
username = models.CharField(max_length = 200)
# put other fields like password etc. here
class Team(models.Model):
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
user = models.ManyToManyField("User")
class Schedule(models.Model):
user = models.ForeignKey("User")
team = models.ForeignKey("Team")
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
Note the following:
You don't need to have a primary key field in the models because Django adds a primary key field called pk or id automatically.
Note the absence of the User Belongs To model. Django implements join-tables like User Belongs To automatically when you use a ManyToManyField. See the Django docs on many-to-many relationships.
You also don't need on_delete = models.CASCADE on ForeignKey fields, because this is the default behavior.
To see how to get information about users, teams and schedule from this configuration of models, consult the Django documentation on making db queries. It's quite easy.
I have to implement two models in a django project --> Country and Continent.
It is possible to import all information about countries and continents from an XML file that populates the database with these two tables.
I've implemented them in this way
from django.db import models
class Continent(models.Model):
name = models.CharField(max_length=255, unique=True)
code = models.CharField(max_length=255, unique=True)
countries = ?
class Meta:
ordering = ['name']
class Country(models.Model):
name = models.CharField(max_length=255)
capital = models.CharField(max_length=255)
code = models.CharField(max_length=255, unique=True)
population = models.IntegerField(default=0)
area = models.IntegerField(default=0)
continent = models.ForeignKey(Continent)
class Meta:
ordering = ['name']
You can see a ? mark in Continent.countries because I don't understand how to implement it. The problem is: "Countries of a continent should be accessible through attribute countries of class Continent"
This means that it is possible to do this:
from MyApplication.model import Country, Continent
europe = Continent.object.get(code=u'eu')
finland = europe.countries.get(code=u'fi')
I've tried models.ForeignKey, but it doesn't work.
It says that "Nonetype object doesn't have any get method"
Can anyone help me please?
Thanks
Django does not support one to many directly, instead you can use the reverse of one-to-one relation to get a one-to-many relation.
So, go ahead with the other approach of using many to one by adding foreign key inside the country relating to continent. Now, you have a one-to-one from country to continent. Next, do a reverse query from Continent's object to get the desired relation. Take a look:
class Continent(models.Model):
...
class Country(models.Model):
...
continent = models.ForeignKey(Continent, related_name="countries")
...
europe = Continent.object.get(code=u'eu')
finland = europe.countries.get(code=u'fi')
I'm interacting with a legacy db on another system, so the models are written in stone and not very django-ey.
My models.py:
class Site(models.Model):
site_code = models.CharField(max_length=30, primary_key=True)
name = models.CharField(unique=True, max_length=300)
class Document(models.Model):
id = models.IntegerField(primary_key=True)
site_ref = models.ForeignKey(Site)
description = models.CharField(max_length=1500)
class DocumentStatusCategory(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(unique=True, max_length=90)
class DocumentStatus(models.Model):
id = models.IntegerField(primary_key=True)
document = models.ForeignKey(Document)
status = models.ForeignKey(DocumentStatusCategory)
changed_by = models.ForeignKey(User)
created_at = models.DateTimeField()
In my views.py I want to retrieve a queryset with all the Document objects that belong to a specified Site (say site_ref=mysite) which do not have any related DocumentStatus objects with status=4.
Any idea how I can do this as a single (non-sql intensive) line?
Document.objects.filter(site_ref=mysite).exclude(documentstatus__status_id=4)
Document.objects.filter(site_ref=site_obj).exclude(documentstatus_set__in=DocumentStatus.objects.filter(status_id=4))
Not exactly one query, but I don't think that's achievable without going down to raw sql. Two queries isn't bad though I suppose.
I should mention that the above assumes that the reverse relation between Document and DocumentStatus is documentstatus_set. You can explicitly state what the reverse relation is like so:
# inside the DocumentStatus model definition
document = models.ForeignKey(Document, related_name='document_statuses')
Then the query becomes:
Document.objects.filter(site_ref=site_obj).exclude(document_statuses__in=DocumentStatus.objects.filter(status_id=4))