Django: m2o relation to a m2m table - django

I have a default m2m relationship between Stage and Pipeline (without through model).
I have another model (StageHistory) that needs a m2o relationship with the data saved on the table created by the m2m relationship stage-pipeline.
So what i should write on "pipeline_stage" field ?
class Stage(models.Model):
#other fields
class Pipeline(models.Model):
stages = models.ManyToManyField('Stage')
#other fields
class StageHistory(models.Model):
pipeline_stage = models.ForeignKey(HERE)
Should I create a "through" model ?

You should be able to use Pipeline.stages.through to reference the through table.
If not, you could use an explicit through table and use that as the FK target.

Related

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

You cannot alter to or from m2m fields or add or remove through =onmn2m fields

What is this error:
You cannot alter to or from m2m fields or add or remove through=on m2m fields
Class post(models.Model):
Title=models.CharField(max_length=50)
Class cat_child(midels.Model):
name=models.CharField(max_length=50)
post=models.ManyToManyField(Post)
cat_parent=models.ForeignKey('Cat_Parent',on_delete=models.CASCADE)
Class cat_parent(models.Model):
name=models.CharField(max_length=50)
Why is that?
Django by default creates an intermediate table, but if you want to specify one manually you must do through through ManyToManyField (referring to the intermediate table)
class Category(models.Model):
Name=models.CharField(max_length=50)
post=models.ManyToMany(Post, through='PostCat')
and Then specify the intermediate table as it did.
The only change would be to add the through = 'PostCat' in ManyToMany where PosCat is the intermediate table referenced.
You can find more in the documentation, but basically that is the solution:
https://docs.djangoproject.com/en/2.1/topics/db/models/

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 Show M2M field in either model when using forms.ModelForm

I am using the forms.ModelForm to create my form. I want to be able to show the manytomany field in both model forms, how do I do this?
If the manytomany relationship is defined in the model it is fine and just appears but if it is not in the model (but is still linked via the other model) it does not appear. How can I make it show up?
Hope this makes sense.
Thanks
Use this third party model field class. It's a four-liner that subclasses the regular ManyToMany class, but instructs Django not to create a separate table for the second relationship.
You create the relationship on the first model normally, explicitly specifying database table name ("db_table" option):
class FirstModel(models.Model):
second_model = ManyToManyField('SecondModel', related_name='second_model', db_table=u'TABLE_FOR_FIRST_AND_SECOND_MODEL')
...
And for the second model use ManyToManyField_NoSyncdb, so it doesn't try to create a second table:
class SecondModel(models.Model):
first_model = ManyToManyField_NoSyncdb('FirstModel', related_name='first_model', db_table=u'TABLE_FOR_FIRST_AND_SECOND_MODEL')
...
For more information refer to the right-hand description on django snippets.

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