I have just started learning Django and one thing in models about ForeignKey was unclear to me.
So lets say I have one model like this:
class Webpage(models.Model):
name = models.CharField(max_length=264, unique=True)
url = models.URLField(unique=True)
name2 = models.CharField(max_length=264, unique=True)
class Records(models.Model):
site = models.ForeignKey(Webpage)
So when creating Records entry for testing I see ForeignKey is referenced to Name field of Webpage. My confusion is why exactly name? As I know ForeignKey is referencing to primary key and if you are not giving primary_key attribute to any fields it will create 'id' field and make that as primary_key. So then why not 'id' field but 'name'.
Sorry if this is repeat question, I just couldn`t find answer.
#Orkhan Rustamli
If you are try to list all yours records and get the name of webpage I think it's because your print method on webpage class is set to return the name of attribute.
if you want to return the id you will set the return function like:
class webpage(models.Model):
pass
def str(self):
return self.id
Related
The following sample database stores posts of news and relevant information for each piece of news. I'm interested in retrieving the topics associated with each news. The problem is, they are stored in different tables with complex relationships.
Each news is assigned with a newsid in the table NewsFeed:
class NewsFeed(models.Model):
newsid= models.OneToOneField('NewsSub',
on_delete=models.CASCADE, db_column='newsid',
primary_key=True)
def __str__(self):
return str(self.newsid)
An one-to-one relationship is defined between the field newsid in the class NewsFeed and the model NewsSub:
class NewsSub(models.Model):
newsid = models.BigIntegerField(primary_key=True)
In another class NewsTopic, a foreignKey relationship is defined between the field newsid with the model NewsSub:
class NewsTopic(models.Model):
newsid = models.ForeignKey(NewsSub, on_delete=models.DO_NOTHING,
db_column='newsid')
topicid = models.ForeignKey(NewsLabel, on_delete=models.DO_NOTHING,
db_column='topicid', related_name = 'topic')
In the NewsTopic db table, each newsid may correspond to more than one topicid. Finally, the field topicid of the class NewsTopic is related to the model NewsLabel:
class NewsLabel(models.Model):
topicid = models.BigIntegerField(primary_key=True)
topiclabel = models.CharField(max_length=100)
def __str__(self):
return self.topiclabel
In the NewsLabel db table, each toicid corresponds to a unique topiclabel.
My goal is to retrieve the topiclabel(s) associated with each NewsFeed object, by querying the newsid. Suppose result represents one such object, I'm wondering is it possible to do something like result.newsid.topicid.topiclabel?
Thanks and sorry for the long descriptions!!
#EvelynZ
You can use the prefech_related to fetch the values of the related object, please check the https://docs.djangoproject.com/en/2.1/ref/models/querysets/#prefetch-related
I'm making one of my first django apps with sqlite database. I have some models like for example:
class Connection(models.Model):
routeID = models.ForeignKey(Route, on_delete=models.CASCADE)
activityStatus = models.BooleanField()
car = models.ForeignKey(Car, on_delete=models.CASCADE)
class Route(models.Model):
name = models.CharField(max_length=20)
and forms
class RouteForm(ModelForm):
class Meta:
model = Route
fields = ['name']
class ConnectionForm(ModelForm):
class Meta:
model = Connection
fields = ['routeID', 'activityStatus', 'car']
And in my website, in the url for adding new Connection, I have cascade list containing RouteIDs. And I'd like it to contain RouteName, not ID, so it would be easier to choose. How should I change my ConnectionForm, so I could still use foreign key to Route table, but see RouteName instead of RouteID?
For now it's looking like this, but I'd love to have list of RouteNames, while still adding to Connection table good foreign key, RouteID
Update the Route Model's __str__ method:
class Route(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
Because the __str__() method is called whenever you call str() on an object. Django uses str(obj) in a number of places like in Modelform. By default it returns id or pk that is why you were seeing ids in model form. So by overriding it with name, you will see the names appear in choice field. Please see the documentation for more details on this.
So I have two models:
class UserData(models.Model):
""" Holds basic user data. """
id = models.IntegerField(primary_key=True, editable=False) # id is taken from data.
class ConsumptionTimePoint(models.Model):
""" Individual consumption time points with a One-to-Many relationship with UserData """
user_data = models.ForeignKey(UserData, on_delete=models.CASCADE)
And when I try and test them by creating them both, and their relationship in a test:
def test_basic_model_creation(self):
user_data_object = UserData.objects.create(id=1)
user_data_object.save()
consumption_time_point_object = ConsumptionTimePoint.objects.create(user_data=user_data_object)
consumption_time_point_object.save()
self.assertIsNotNone(consumption_time_point_object.user_data)
self.assertEquals(1, len(user_data_object.consumption_time_point_set.all()))
I get the following error:
AttributeError: 'UserData' object has no attribute 'consumption_time_point_set'
But from my understanding that's the correct way to get the set. Have I misnamed something? Or is this a testing issue?
To get the related queryset the class name is lowercased and _set is appended. Try consumptiontimepoint_set
You can also set the reverse relation name manually by using the related_name parameter.
I'm having trouble running a Django query (v1.9) within my views page. I'm basically retrieving one record from the primers table (that's working fine), then trying to retrieve the corresponding record from the 'gene' table:
models.py:
class Gene(models.Model):
GeneName = models.CharField(max_length=10, unique=True)
ChromosomeNo = models.CharField(max_length=2)
class Primer(models.Model):
PrimerName = models.CharField(max_length=20, unique=True)
Gene = models.ForeignKey(Gene)
views.py
def PrimerDetail(request, pk):
primer_info = get_object_or_404(Primer, pk=pk)
Gene_info = Gene.objects.get(Gene_id = primer_info.GeneName)
The problem appears to be with my use of primer_info.GeneName. I get:
'Primer' object has no attribute 'GeneName'
Change it to primer_info.Gene and I get:
Cannot resolve keyword 'Gene_id' into field. Choices are: ChromosomeLoc, ChromosomeNo, Comments, Disease, Disease_id, GeneName, NoExons, id, primer`
I can substitute for a string value and it works fine. How should I reference a field that is a foreign key object in this context?
with the above description you can try out one more way of getting the Gene object this is follows as.
Gene_info = Gene.objects.get(pk = primer_info.Gene.id)
this would give you the object of Gene object that is foreign key in the Primer Table.
Well it's because you never have a field called Gene_id in your Primer model. Since Gene is the foreign key in Primer, it's easy to get Gene_info:
Gene_info = primer_info.Gene
If you want to query directly on Gene model(which is pretty unnecessary in your case), do:
Gene_info = Gene.objects.get(primer__id=primer_info.id)
I have the following models
class Person(models.Model):
name = models.CharField(max_length=100)
class Employee(Person):
job = model.Charfield(max_length=200)
class PhoneNumber(models.Model):
person = models.ForeignKey(Person)
How do I access the PhoneNumbers associated with an employee if I have the employee id?
Currently I am using
phones = PhoneNumbers.objects.filter(person__id=employee.id)
and it works only because I know that the employee.id and person.id are the same value, but I am sure this is the incorrect way to do it.
Thanks
Andrew
You can (and should) filter without knowing the foreign key field:
PhoneNumber.objects.filter(employee=your_employee).all()
You could do:
employees = Employee.objects.filter(id=your_id).select_related()
if employees.count() == 1:
phone_numbers = employees[0].phonenumber_set.all()
That should get you all your phone numbers in one db query.
By default you can access models related through a foreignkey on the "opposite" side by using "model name in all lower case" followed by "_set". You can change the name of that accessor by setting the related name property of the foreignkey.