Django Two foreign key - django

I have two models: UserProfile (extended from user) and Cv. I created another model that have two foreign key that come from theses models.
class cv(models.Model):
user = models.ForeignKey(User, unique=True)
cv_d= models.TextField(max_length=1100)
...
class cvv(models.Model):
user = models.ForeignKey(User)
cv= models.ForeignKey(cv)
date = models.DateTimeField(auto_now=True)
In my view, I am trying to insert value on cvv:
...
obj = cv.objects.get(pk=id,active=True)
add=cvv(user=request.user, cv=obj)
add.save()
But, I am getting the following error:
(1452, 'Cannot add or update a child row: a foreign key constraint fails
How can I insert theses 2 foreign key on my model?

Welcome to one of the many reasons why you shouldn't use MySQL. This happens most often when you have one table that is MyISAM and one table that is InnoDB. Since myISAM doesn't support FK constraints all hell breaks loose when django creates a FK between the tables.
The fix is to either make both tables InnoDB or MyISAM and not to mix them. Or even better drop the bad RDMS for something not MySQL.

Related

Which one is better for creating a follower-following system, Foreign Key or ManyToMany in django?

Which one would be optimal for creating the followers-following system in Django.
1.Foreign Key
class Follower(models.Model):
current_user = models.ForeignKey(User,on_delete=models.CASCADE,related_name='following')
following_id = models.ForeignKey(User,on_delete=models.CASCADE,related_name='followers')
2.Many-To-Many
class Follower(models.Model):
current_user = models.ForeignKey(User,on_delete=models.CASCADE,related_name='following')
followers = models.ManyToManyField(User)
So, for instance, if we want to retrive the following list of the user:
1.Foreign Key
Follower.objects.get(following_id=1).following.all()
2 Many-To-Many
User.object.get(user=1).follower_set.all().values('current_user')
If you want to add metadata about someone following you don't have much choice but to use a M2M with a through table. Otherwise, you might as well use option 1.

Join and query Django models on non-primary-key relationship?

I've got two models that are logically related through a field that is not the primary key. Is it possible to query them (ex, select_related(…)) without introducing a ForeignKey column?
For example, consider the contrived models:
class LogEntry(Model):
source_name = CharField(…)
log_message = CharField(…)
class LogSource(Model):
name = CharField(…)
domain = CharField(…)
I would like to be able to query LogEntry, joining in and filtering on the related LogSource (ex, so I can access log_entry.source without additional queries):
LogEntry.objects
.select_related(
source=Join(LogSource, on="logsource.name = logentry.source_name")),
)
.filter(source__domain="example.com")
Is this possible without introducing a ForeignKey?
You should be able to do this by using extra() with the tables option.
LogEntry.objects.extra(
tables=['logsource'],
where=['logsource.name=logentry.source_name',
'logsource_domain="example.com"',
]
)
Another option is to change source_name to a foreign key, but specify the db_column and to_field arguments to use the existing columns. I know that you said that you didn't want to add a foreign key, but it might be acceptable because it only changes the models, not the columns in the database tables. However, be aware that Django might want to create a foreign key constraint. One hack would be to fake that migration so that the constraint isn't created in the db.
class LogEntry(Model):
source_name = models.ForeignKey(db_column=source_name', to_field='name')
log_entry.source_name would then be the LogSource instance, and log_entry.source_name_id would be the value stored in the source_name column. It might make sense to rename the field from source_name to source after converting to a foreign key, but that's not necessary.

In Django, what's the best way to set up optional foreign keys if most of the foreign keys are blanks?

From questions like this one, I know that the recommended way to make optional foreign keys in django is to set null=True, blank=True. That way, the value of the foreign key does not have to be set.
This seems fine to me if the foreign key is frequently used in the model. But if the majority of the foreign keys are null values, then wouldn't this violate first normal form and create a lot of wasted space?
Sure, the topic of null values in databases may be controversial, but I still wonder how I should set up optional foreign keys in Django if I know that the foreign key will be sparse. Does Django already take this into account? Should I create a separate model for this relationship? Has this already been taken into account during the design of Django?
Thanks.
You can simulate a nullable foreign key by using a third table:
class City(models.Model):
name = models.CharField(max_length=80)
class Person(models.Model):
name = models.CharField(max_length=80)
class PersonCity(models.Model):
person = models.ForeignKey(Person, unique=True)
city = models.ForeignKey(City)
This way, you will only create a row in the table PersonCity for those people with a known City. To access the city of a given person you would use:
city = person.personcity_set().first().city
You can create a custom manager to shorten this syntax and check for a null personcity_set which I didn't for the sake of example, but I personally think that creating a nullable foreign key is still easier to read and debug.

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