How to write Foreign Key to an attribute of other model? - django

I want to create a model that joins two tables in my DB. When writing the foreign keys like this:
fromnode = models.ForeignKey(znode.code)
tonode = models.ForeignKey(znode.code)
there is an error: type object 'znode' has no attribute 'code', but there is such an attribute in znode:
class znode(models.Model):
code = models.DecimalField(max_digits=65535, decimal_places=65535, blank=True, primary_key=True)
How do I write this correctly?

Just use the class name znode instead of znode.code. Django automatically adds an id column to every model which will be used as reference as mentioned in the documentation.
Behind the scenes, Django appends "_id" to the field name to create its database column name. In the above example, the database table for the Car model will have a manufacturer_id column.
Also you should use CamelCaseClassNames to meet pep8 coding style conventions.

Related

How to get all id from model in django [duplicate]

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.

How django creates internal tables dynamically for many-to-many fields

My model :
class Image(models.Model):
name=models.CharField(max_length=40,unique=True,help_text="name of the image")
tags = models.ManyToManyField(Tag)
class Tag(models.Model):
tag = models.CharField(max_length=100,unique=True)
here when I do makemigrations and migrate it is creating 3 tables inside my database 1.image 2.tag 3.image_tags table
so, my question is i am not specifying image_tags table in my models.py file ,from where django is creating image_tags table and what is the flow ??
I have checked in migrations file but I didnot get any clarity regarding this
An intermediary table is required for a Many-To-Many relationship in a database, and because most of the time you don't need to store extra data on the relationship, Django just silently creates this table for you. In your case it will create a table with 3 fields: id, image_id, tag_id.
If you want to specify your own intermediary table, for example if you want to store extra data, you can create a model with ForeignKey's to your related tables and then define your ManyToManyField with a "through" argument like so:
class ImageTag(models.Model):
image = models.ForeignKey('Image')
tag = models.ForeignKey('Tag')
extra_data = models.CharField()
class Tag(models.Model):
name = models.CharField()
class Image(models.Model):
name = models.CharField()
tags = models.ManyToManyField(Tag, through=ImageTag)
Actually, that is not Django Functionality. It's SQL functionality. SQL is creating the internal table. Because SQL can't create reference, it's not Foreign key. That's why this Bridging table concept is emerged. It will resolve the problem as well as it will hold data(ID) of both tables and few custom fields, depends on requirements.
Updated with new req:
Refer this:
https://gist.github.com/jacobian/827937
Django 1.8 - Intermediary Many-to-Many-Through Relationship - What is the consequence of where 'ManytoManyField' is used?
From my point of view, It's not good practice to customize the bridging table. You can specify the extra fields to any of two tables orelse create a new table make it as foreign key

Foregin key field name is followed by _id

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);

Django. Many-To-Many Field for form, but not for model

I have DB that should have one field with type Many-To-Many, but it is not and I can't change this.
For example I have a list of students and a list of subjects. Subject should be many-to-many field in students table, but as i said it is not. Students table doesn't have this field at all. But there is still another table students-subjects that contains subject_id-student_id items.
How can I embed in student form some kind of subject field that could change students-subjects data when I save a student in DB? The problem is that I can't change the DB structure so need to make it only with help of Django.
There is no such thing as a 'Many-to-many field' for a database-table like you might know it of foreign keys. In database representation many-to-many relationships are realized by using an extra table that links the primary keys (usually the ids) of the records you want to set in relation. In your case that is the table students-subjects. Django uses this table when you define a many-to-many relationship in the model. You do not have to change your database structure at all, it will be working perfectly as it is now.
See the documentation: ManyToManyField
You'll have to set the db_table option with the name of your intermediary table (i.e. students-subjects). Then everything should work fine.
EDIT:
Considering your comment, the problem is that Django expects a certain naming convention (i.e. MODELNAME_id) which isn't provided by your table. Since you say that you cannot change the table itself, you have to try something else.
You have to create an extra Model for your intermediary table (students-subjects) and define the field 'students' as a foreign key to the students model and the field 'subjects' as a foreign key to the subjects model. Then for the many-to-many field you specifiy the option 'through' with the name of your intermediary table. Set the options 'db_column' to let Django know which names you'd like to use for the databse columns. 'db_table' in the meta class is needed to specify your database table name.
You get something like:
class StudentsSubjects(models.Model):
student = models.ForeignKey(Student, db_column='student')
subject = models.ForeignKey(Subject, db_column='subject')
class Meta:
db_table = 'students-subjects'
class Student(models.Model):
...
subjects = models.ManyToManyField(Subject, through='StudentsSubjects')
...
class Subject(models.Model):
...
I hope that will help you.
For more detail see: Extra fields on many-to-many relationship.

Django model with 2 foreign keys from the same table

I wanted a Django model with 2 foreign keys from the same table. It's an event table which has 2 columns for employees: the 'actor' and the 'receiver'. But I get this error:
Error: One or more models did not validate: tasks.task: Intermediary
model TaskEvent has more than one foreign key to Employee, which is
ambiguous and is not permitted.
Is there a better way to model this?
I think I'm going to add a TaskEvent_to_Employee table. There will be two records in it, one for each of the two employees related to each TaskEvent. Does anyone know an easier workaround?
I haven't done this yet, but I used inspectdb to generate the models.py file from an existing DB that does exactly that - this is what inspectdb threw back, so it should work:
creator = models.ForeignKey(Users, null=True, related_name='creator')
assignee = models.ForeignKey(Users, null=True, related_name='assignee')
Hope that works for you - if it doesn't I am going to have a problem too.
I think what you're looking for is the related_name property on ForeignKeyFields. This will allow you to reference the same table, but give django special names for the relationship.
More Info:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
https://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/
From the error message, it sounds like you're trying to put two foreign keys to the same object on an intermediary table used via the through argument to ManyToManyField, the documentation for which states:
When you set up the intermediary
model, you explicitly specify foreign
keys to the models that are involved
in the ManyToMany relation. This
explicit declaration defines how the
two models are related.
There are a few restrictions on the
intermediate model:
Your intermediate model must contain one - and only one - foreign key to
the target model (this would be Person
in our example). If you have more than
one foreign key, a validation error
will be raised.
Your intermediate model must contain one - and only one - foreign key to
the source model (this would be Group
in our example). If you have more than
one foreign key, a validation error
will be raised.
Using related_name was my solution:
class Sample(models.model):
...
class Mymodel(models.model):
example1 = models.ForeignKey(Sample, related_name='sample1')
example2 = models.ForeignKey(Sample, related_name='sample2')
The fact that two columns are part of one table implies that the two fields are related, therefor to reference them individually is not ideal. The ForeignKey of your model should be the primary key of the table you are referencing:
event = models.ForeignKey('event')
You would then reference the columns as such:
foo.event.actor
foo.event.receiver
If you wish you could also change the way your class/model references the foreign attributes with properties. In your class you would do the following:
#property
def actor(self):
return self.event.actor
#property
def receiver(self):
return self.event.receiver
This would allow you to then call foo.actor and foo.receiver but I believe the longer, foo.event.actor would be more pythonic