In a model, when a foreign key field is created then Django apparently create another field with the same field name followed by _id.
for example if I have
class Post(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,default=None)
dated = models.DateTimeField(auto_now=True)
...
Then I will have the following fields available:
id,user,user_id,dated
I am not sure why this field (user_id) was added?
Later I wanted to override my queryset in a class view
so I was confused which one to use (user field or user_id field)
:
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
Or
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user=self.request.user.id)
I tried both and both worked just fine
My question is:
1) What is the purpose of creating this additional field ?
2) What is the difference between the original foreign key field (user in my case) and user_id field?
3) Will both fields user and user_id available in the database? what is the point of that?
4) Is the content of user and user_id identical in each record? if so ,then what the purpose of this additional field that was created automatically by django?
Thanks a lot
Django only creates one column in the database for the foreign key.
The difference between the field and the _id attribute it generates is that accessing the field performs a query for the full set of columns from the related table in order to construct the complete related object. If you want the full object, use the field (and probably also use select_related() in the initial query to save you from doing N+1 queries).
On the other hand, if all you need is the DB-level value of the foreign key, which is usually the primary key of the related object (and often that is what you want), the _id attribute shortcut is there for you and already has the data, because that's what was actually in the foreign key column.
In other words, suppose I have models like this:
class ModelA(models.Model):
name = models.TextField()
class ModelB(models.Model):
name = models.TextField()
a_instance = models.ForeignKey(ModelA)
If you query for a ModelB, like ModelB.objects.get(pk=12), you'll get a query like this:
SELECT id, name, a_instance_id
FROM your_app.modelb
WHERE id = 12;
Notice a_instance_id is the name of the column -- it's just a foreign key, all it stores is a pointer to the primary key of a ModelA instance. If you just need that primary key, accessing the a_instance_id attribute has it already without needing to do another query. If you access the a_instance field, though, you get to do another query:
SELECT id, name
FROM your_app.modela
WHERE id = (whatever the value of that foreign key was);
Related
I have a table called user_info. I want to get names of all the users. So the table has a field called name. So in sql I do something like
SELECT distinct(name) from user_info
But I am not able to figure out how to do the same in django. Usually if I already have certain value known, then I can do something like below.
user_info.objects.filter(name='Alex')
And then get the information for that particular user.
But in this case for the given table, I want to get all the name values using django ORM just like I do in sql.
Here is my django model
class user_info(models.Model):
name = models.CharField(max_length=255)
priority = models.CharField(max_length=1)
org = models.CharField(max_length=20)
How can I do this in django?
You can use values_list.
user_info.objects.values_list('name', flat=True).distinct()
Note, in Python classes are usually defined in InitialCaps: your model should be UserInfo.
You can use values_list() as given in Daniel's answer, which will provide you your data in a list containing the values in the field. Or you can also use, values() like this:
user_info.object.values('name')
which will return you a queryset containing a dictionary. values_list() and values() are used to select the columns in a table.
Adding on to the accepted answer, if the field is a foreign key the id values(numerical) are returned in the queryset. Hence if you are expecting other kinds of values defined in the model of which the foreign key is part then you have to modify the query like this:
`Post.objects.values_list('author__username')`
Post is a model class having author as a foreign key field which in turn has its username field:
Here, "author" field was appended with double undersocre followed by the field "name", otherwise primary key of the model will be returned in queryset. I assume this was #Carlo's doubt in accepted answer.
I am just starting out with Django and so please help me out with my doubt. Currently, I have three tables Topic, Webpage, and AccessRecord. In the third table AccessRecord, I have used a ForeignKey with the second table Webpage. But Webpage table has three attributes topic, name, and URL ..so my doubt is which attribute of these three will be treated as a Foreign key to AccessRecord table.
Any help will be greatly appreciated.
class Topic(models.Model):
top_name = models.CharField(max_length=264,unique = True)
def __str__(self):
return(self.top_name)
class Webpage(models.Model):
topic = models.ForeignKey(Topic,on_delete=models.CASCADE)
name = models.CharField(max_length=264,unique=True)
url = models.URLField(unique=True)
def __str__(self):
return self.name
class AccessRecord(models.Model):
name = models.ForeignKey(Webpage,on_delete=models.CASCADE)
date = models.DateField()
def __str__(self):
return str(self.date)
Actually, the ForeignKey relationship is from AccessRecord to Webpage object, that only resides in AccessRecord. There is no direct relation between a Webpage to a AccessRecord object. Instead, django provides a reverse relationship where you can access queryset of AccessRecord from a Webpage object. Like this:
webpage = Webpage.objects.first() # an object
records = webpage.accessrecord_set.all() # a queryset
If you iterate through records variable given above, you shall get AccessRecord object. Like this:
for record in records:
print(record) # an AccessRecord object
Truth is the foreign key relationship goes this way
Topic -(1------many)->webpage --(1------------many)-> Accessrecord
In this situation, Accessrecord is also linked to Topic through webpage.
Django will also automatically create a primary key for you.
I also notice something intriguing while playing about with Django ORM.
Note that what you set on the def str: method is what the foreign key field will be filled with.
i.e.
your model webpage returns self.name, the field name from inheriting model Accsessrecord will have options from the self.name.
It cant be filled manually, this way Django maintains data integrity.
You can play around it on your admin page as well.
Hopelly this also helps
I have a django model (say model1) where I have my own primary key, but now I want to change the primary key to default id field. But the problem if I try to change is, I have another model (say model2) which has many to many dependency to the model1 and it is causing errors when I am trying to modify the field.
Is there any way I can change the primary key of this model?
ex:
class model2(models.Model):
id = ..
...
model1 = models.ManyToManyField("model1", blank=True)
classs model1(models.Model):
Name = models.charField(primary_key=True, max_length=280)
..
Now I want to change the primary key of model1 back to Id.
I wanted all instances in all tables to have an object instance. A one to one primary key field looked like a good way to do this. Like a small example below.
from util.fields import BigAutoField,BigForeignKey
from django.db import models
class Common_document(models.Model):
pk = models.OneToOneField("Type_object", primary_key=True, related_name="common_document_content_pk")
author = models.ManyToManyField("Type_object", related_name = 'common_document_author',
limit_choices_to = {"Common_document_author_author":"Type_object"} ,null = True,
through = 'Common_document_author', blank = True)
#....
class Common_document_author(models.Model):
pk = models.OneToOneField("Type_object", primary_key=True, related_name="common_document_author_pk")
document = BigForeignKey("Common_document", related_name='Common_document_author_document')
author = BigForeignKey("Type_object", related_name='Common_document_author_author')
class Type_object(models.Model):
id = BigAutoField(primary_key=True)
#....
# Some of the fields are m2m
However this gave the following error:
django.core.management.base.CommandError: One or more models did not validate:
schema.common_document: Intermediary model Common_document_author has more than
one foreign key to Type_object, which is ambiguous and is not permitted.
This error is removed if I comment out the pk field in the document_author table. I guess the error comes because django is not sure witch object FK to use. How do i fix this? Is there a way to tell django which field in the m2m table to be used in the m2m field?
I am probably not going to do it like this. m2m tables are probably not going to need to have an object instance, but I would still like to know how to do this.
I guess I don't understand you motivation. Why do you want to use a foreign key as your primary index? Sure, index it, but primary?. You might also try changing its name from 'pk', I am sure Django makes assumptions about the field called 'pk'.
In my ModelForm's save() method I am accessing self.changed_data and I would like to do something like:
changes_moderated_dict.update(dict(
[(i, staff.profile.user.__dict__[i])
for i in changed_data
if i in staff.profile.user.__dict__]))
which updates changes_moderated_dict with staff.profile.user key/value pairs if the key is found in changed_data. changes_moderated_dict is basically used to store all the field changes made to this particular model inside the form (for later processing and serialization).
This works all fine as long as the staff.profile.user is not a foreign key relationship in which case the filed name has a _id suffix and would not match up with the self.changed_data field name which is the attribute name as it appears in the model (without _id).
Is there a way do resolve the foreign key attribute inside a model's __dict__ to it's actual name so that the above method still works?
I'm not sure what the goal of accessing user.__dict__ is, but if it is to check the model fields you can do something like this:
u = staff.profile.user
model_field_names = map(lambda f:f.name, u._meta.fields)
changes_moderated_dict.update(dict(
[(i, getattr(u, i, None))
for i in changed_data
if i in model_field_names]))