How do I travel through multiple foreign keys in Django? I've tried everything I can think of from the django docs, but I'm obviously missed something (extreme newbie). I have models for scientists, experiments, and theories.
If I want to look at a particular Theory (let's call it 'relativity') and get a list of all of the emails of scientists working on it (kept in the normal django user model), how do I do this?
class Experiment(models.Model)
experimenter = models.ForeignKey(Scientist)
theory = models.ForeignKey(Theory)
class Theory(models.Model)
name = models.CharField(max_length=100)
class Scientist(models.Model)
user = models.ForeignKey(User, unique=True)
institution = models.CharField(max_length=20, null=True, blank=True)
These are simplified versions of my models that I rewrote, so there are probably some errors in it, but the relationships are correct.
I've tried every kind of combinations of select_related(), get(), filter() but can't figure it out. Thanks in advance for your help!
User.objects.filter(scientist__experiment__theory__name=u'relativity')
Take a look at the Django documentation section about Lookups that span relationships. The net takeaway is:
To span a relationship, just use the field name of related fields across models, separated by double underscores, until you get to the field you want.
Ignacio's answer shows an example of using the double underscores on field names to span a relationship.
The other relevant portion of Django's documentation would be the Related objects section. Relationships in Django are asymmetrical in the way they are accessed. Forward/normal relationships are accessed as attributes of the models. Backward relationships are accessed:
Django also creates API accessors for the "other" side of the relationship -- the link from the related model to the model that defines the relationship. For example, a Blog object b has access to a list of all related Entry objects via the entry_set attribute: b.entry_set.all().
Related
I'm trying to find a solution to the following problem with django models:
The app would add products to a shopping cart. The problem is that those products come from different models, and no matter where they come from, I'd like to use one ManyToManyField to incorporate them.
Suppouse I've two different kind of products from two different models:
Class ListOfProducts1(models.Model):
name= CharField()
price= IntegerField()
Class ListOfProducts2(models.Model):
name=CharField()
price=IntegerField()
The following model would be used for get the quantity and the product added(and then related to one particular order).
Here is the problem. Look to the field itemsadded, where I want to relate this field to ListOfProducts 1 and 2. I'd put both of them into the same field, but I've already know this is not possible. Just for better understanding of the problem here you have:
Class ProductsOrdered(models.Model):
itemsadded= OneToOneField(ListOfProducts1 and ListOfProducts2,on_delete=models.CASCADE)
Quantity = IntegerField()
Then the Order's model:
Class Orders(models.Model):
cart= ManyToManyField(ProductsOrdered)
The OneToOne fields can refer to only one table.
But you can use either GenericForeignKey or alternatives (which is better).
Look at this article: Avoid Django’s GenericForeignKey. It describes alternatives, such as:
nullable fields on source table
intermediate table with nullable fields
intermediate table with OneToOneFields on destination models
multi-table inheritance
multiple linked models
First of all, yes: I've read Django's foreign key and many-to-many documentation, but I'm still not 100% clear on how to implement relationships on a practical level, especially regarding the hierarchy of the relationships.
One-to-one
I am aware of how to form one-to-one relationships. However, on a more conceptual level, which model should contain that reference to the other one? Let's say I have a Citizen, and a Passport. Now, it's obvious that one Citizen can only have a single Passport and viceversa, but, ideally, should the Citizen contain a field referencing to his Passport, or should the Passport model contain a reference to the Citizen it belongs to?
Many-to-many
For the sake of simplicity, let's say I have a Person model and a Trip model (Trip as in going out on a trip somewhere). Many Persons can participate in a single Trip. Or in other words: a Person can participate in many Trips and in any single Trip, a lot of Persons can participate. This looks like a many-to-many relationship, but, again, ideally, which model should contain the definition for the relationship, the Person with a trips field or the Trip with a participants field? And why? Does it even make any practical difference?
Thank you.
This depends on your business logic. As a rule of thumb I'd suggest to think about the admin app. How would you like to add new objects?
When adding new objects, how would you like to add related objects?
Let's say you have these models:
Citizen(models.Model):
name = models.CharField()
Passport(models.Model):
number = models.CharField()
citizen = models.OneToOneField('Citizen', related_name='passport')
When adding new passport object, you have the possibility to add new citizen, if it doesn't yet exist. Since this doesn't look very logical to me, I'd change the relation as:
Citizen(models.Model):
# other fields
passport = models.OneToOneField('Passport', related_name='citizen')
Now we can add a new citizen object in the admin and add the related passport object within the same page.
If you use the admin app, this should lead you to more ergonomical design.
EDIT: expand with many-to-many example
Better example for a m2m relation would be StackOverflow - there are questions and tags. A question has many tags, and a tag has many questions. Let's say the models look like this:
Question(models.Model):
title = models.CharField()
body = models.TextField()
author = models.CharField()
tags = models.ManyToManyField('Tag', related_name='questions')
Tag(models.Model):
name = models.CharField()
Why do we put the relation in Question? This should be very logical - when creating a new question you'd like to set the tags for it. When creating a new tag you don't care about any questions associated with it. You can create a tag and later when creating questions, associate them with the tag.
If a tag doesn't exist yet you can add it from the admin, when adding a new question.
I hope this second example is more palpable.
The theory behind this is called database normalization which is a ladder of best practices you should look up if you want to know more about how to structure your data.
The third form tells us that:
"[Every] non-key [attribute] must provide a fact about the key, the whole key, and nothing but the key."
So in the case of ForeignKey fields it should be on the Child model, because it doesn't tell us anything about the parent, but it does tells us what parent the child belongs to.
The mental model that you should have is Parent and Child. Every relationship has two models. So think of one as the Parent model or the Primary model and think of the other one as the Child model or the Secondary model.
NOTE: Always put your relationship field in the CHILD model.
Here is how I would solve your problems:
For the first one, I will have a mental model that Citizen is the Parent and Passport is the child.
class Citizen(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Passport(models.Model):
owner = models.OneToOneField(Citizen)
unique_no = models.CharField(max_length=30, unique=True)
For the second problem, do the same. I would choose Person as the parent model and Trip as the child model.
class Person(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Trip(models.Model):
person = models.ManyToManyField(Person)
info = models.TextField()
If you have sqlitebrowser, you can use that to open your database and check what tables were created according to your models. Then, you will have a clearer idea as to how Django sees your models.
I am working in django, am planning a database for rides for users.
each User can be on multiple Rides (over time) and each Ride can have multiple Users (passengers) in it.
Also, for each Ride there has to be only one Driver (also a User) so I think I have a many-to many relationship between the Rides and Users tables for what user is on what ride, and also a One-To-Many relationship between the Rides's Driver_id and the User_id. right?
My questions are-
I saw in the django docs that I should put a many-to-many field in One of the models. Does it matter which one? and also, does it create a new table like rides_users?
and also, what is the difference (in One-To-many relationship) between using a foreignKey field and a OneToManyField field?
EDIT:
Currently, there are my models:
def get_image_path(models.Model):
return os.path.join('photos',str(instance.id),filename)
class UserProfile(models.Model):
user=models.OneToOneField(User)
phone_number=models.CharField(max_length=12)
profile_picture=models.ImageField(upload_to=get_image_path, black=True, null=True)
class Ride(models.Model):
driver=models.ForeignKey(UserProfile, related_name="r_driver")
destination=models.ForeignKey(Destination, related_name="r_final_destination")
leaving_time=models.DateTimeField()
num_of_spots=models.IntergerField()
passengers=models.ManyToMany(UserProfile, related_name="r_passengers")
mid_destinations=models.ManyToMany(Destination, related_name="r_mid_destinations")
class Destination(models.Model):
name=models.CharField(max_length=30)
As you can see, each Ride has multiple mid_destination and multiple passengers. a Ride also has One driver and One final destination.
The Issue is - when a User adds a Ride, I want the driver, destination and mid_destinations and the rest of the fields to be set by the User (the driver is user adding the Ride), Except for the passengers field. I want the other Users to add themselves to the ride, so when the Ride is created the User (driver) doesn't have to set the passengers.
How do I go about it? and also, any other suggestions about the models?
There is no such thing as a OneToManyField.
It doesn't matter from a practical point of view which side the ManyToManyField lives on. Personally, I'd put it on Ride, both to avoid changing the User model and because conceptually I'd say that rides are the main objects here.
And yes, adding the field will automatically create the linking table.
what you want is probably something like this
class MyModel(models.Model):
driver = models.ForeignKey(to=User, related_name='r_driver')
# you need to use a related name if you want to link to the same model more than once
passengers = models.ManyToManyField(User, related_name="r_passengers")
I have a reasonably complex custom Django model method. It's visible in the admin interface, and I would now like to make it sortable in the admin interface too.
I've added admin_order_field as recommended in this previous question, but I don't fully understand what else I need to do.
class Book(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=200)
library_id = models.CharField(max_length=200, unique=True)
def current_owner(self):
latest_transaction = Transaction.objects.filter(book=self)[:1]
if latest_transaction:
if latest_transaction[0].transaction_type==0:
return latest_transaction[0].user.windows_id
return None
current_owner.admin_order_field = 'current_owner'
Currently, when I click on the current_owner field in the admin interface, Django gives me
FieldError at /admin/books/book/
Cannot resolve keyword 'current_owner' into field
Do I need to make a BookManager too? If so, what code should I use? This isn't a simple Count like the example in the previous question, so help would be appreciated :)
Thanks!
The Django admin won't order models by the result of a method or any other property that isn't a model field (i.e. a database column). The ordering must be done in the database query, to keep things simple and efficient.
The purpose of admin_order_field is to equate the ordering of a non-field property to the ordering of something that is a field.
For example, a valid values current_owner.admin_order_field could be id, title or library_id. Obviously none of these makes sense for your purpose.
One solution would be to denormalise and always store current_owner as a model field on Book; this could be done automatically using a signal.
You can't do this. admin_order_field has to be a field, not a method - it's meant for when you have a method that returns a custom representation of an underlying field, not when you do dynamic calculations to provide the value. Django's admin uses the ORM for sorting, and that can't sort on custom methods.
I have some newbie questions about Django.
I want to write a generic ticket-management system, where the administrator of the site should be able to add custom fields to a ticket. It seems that the database tables are generated on initialization, so it is not clear to me how to add custom fields at runtime.
One way is to have a long list of fields of different types, all nullable, and let the administrator rename/select the fields she needs. Is there a better design?
Thanks!
I'm currently in charge of maintaining a similar site where a treatment for a medical condition is listed and there can be arbitrary number of "cases" which are user-posted experiences for that treatment/condition combo attached.
The method my company used to set it up was to have an Entry object which would be analogous to the custom field you described, which has a Foreign Key referencing the treatment/condition to which it belongs.
Then when we want to get all the entries for a particular treatment/condition combo, we simply do an
Entry.objects.filter(condition=ID)
So, in your case, I would suggest having a Ticket model, and an "Entry" style model which contains a Foreign Key reference to the Ticket to which it belongs.
I would make something like the code below. Store extra attributes in an attribute model. Store the values in AttributeValue.
class Ticket(models.Model):
name = models.CharField(max_length=200)
class Attribute(models.Model):
name = models.CharField(max_length=200)
class AttributeValues(models.Model):
attribute = models.ForeignKey(Attribute)
ticket = models.ForeignKey(Ticket)
value = models.CharField(max_length=200)