OneToOne field in django default - django

Please help. I have a model:
class Book(core.BaseModel):
book_link = models.OneToOneField('self', default = "", on_delete=models.CASCADE)
book_name = models.CharField('Name', max_length=250)
I want to set 'self' in field book_link that will return in this field - book_name or Book Model object.
But when I create new Book object - Django shows me in column "book_link" all book names which I can choose and save new object. I want that when I created new object it will authomatically save for this object this name!

If I have understood your question, you want to create something like a linked list of books. To do so, first do not use one to one field unless each book is only and only linked to one book. To link one object to itself, you can use the name of model in string format.
And also note the way you had provided default was faulty, It is better to make it nullable with null=True.
My recommended model will be this:
class Book(models.Model):
book_link = models.ForeignKey(to='Book', null=True, on_delete=models.CASCADE, related_name="linked_books")
book_name = models.CharField('Name', max_length=250)

Related

How to define models in django that provides custom values based on pre-selection for a field?

Given the following model that stores the user's wish list for reading books:
class ReadingList(models.Model):
user_id = models.ForeignKey(UserInfo, on_delete=models.DO_NOTHING, null=False, blank=False, default=None, db_column='user_id')
book= models.CharField(max_length=255, blank=False)
creation_time = models.DateTimeField(blank=True)
class Meta:
unique_together = (('user_id', book),)
I want to create a model that helps in tracking the time spent in the reading the book on different days which looks something like this:
class ReadingTracker(models.Model):
user_id = models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='user', blank=False, db_column='user_id')
book= models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='book-to-read', blank=False, db_column='book')
time = models.DateTimeField(blank=True)
time_spent = models.floatfield()
On the client-side (corresponding to ReadingTracker) for both the fields user_id and book
I see that ReadingList object (1), ReadingList object (2), ... are listed. But, this is not working as expected.
What I want to achieve are the following:
For user_id field I want to see the something like dummy_uid1, dummy_uid2, ... to be listed.
Consider dummy_uid1 wants to read book1 and book2 whereas dummy_uid2 wants to read book1 and book3.
When dummy_uid1 is selected as user_id, I want only book1 and book2 to be listed for selection.
How do I define the model in django rest framework to achieve this?
Any suggestions related to the above would be much appreciated and thank you in advance.
There are two parts to this question:
If you want to see a different value than ReadingList object (1) then you need to define the __str__ value of your model, you can do this like so:
class ReadingList(models.Model):
...
def __str__(self):
return f'{self.user_id}' # return whatever string you want to display
If you want to just display the books for a particular user then you can use a filter() (see the Django documentation):
reading_list = ReadingList.objects.get(...)
ReadingTracker.objects.filter(user_id=reading_list)
However, I would add that you have a user_id on your ReadingList object which does seem to connect to a User model, but your user_id on ReadingTracker is a ForeignKey relation to ReadingList, which is confusing. I would suggest renaming the field or actually making it link to the User model (though this is unnecessary as you can still filter by User through the ReadingList model).

How to call a a field of one model A into another model B so that b can work as a view

I have created a model called Department, Course. Models are as follow
This is the model for departments and course
class Departments(models.Model):
Department_Id = models.IntegerField(primary_key=True)
Department_Name = models.CharField(max_length=200)
Department_Code = models.CharField(max_length=200)
class Course(models.Model):
Course_Id = models.IntegerField(primary_key=True)
Department_Id = models.ForeignKey(Departments, on_delete=models.CASCADE)
Course_Name = models.CharField(max_length=200)
Course_Code = models.CharField(max_length=200)
I want to create a model called view which can be later on called for search. I want a view model in a such a way that it consit of the data in concat form i.e. name= Department_name+ Course_Name
class View (models.model):
view_id= models.IntegerField(primary_key=True)
Name= Department_name(I want this from Departments table)
+ Course_Name(I want this from Course table)
I try using one to one relation . I would really appricate the help
It's not clear why you'd want to do that. It's never a good idea to duplicate data from one model into another one, as it can lead to inconsistencies.
You can add a ForeignKey in View to your Course model and then when you do f"{view.course.name} {view.course.department.name}" you already have your string:
class View(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
def name(self):
return f"{self.course.name} {self.course.department.name}"
Notes:
Don't call your foreign key Department_id because it's not referring to the id but to the object itself in the Django ORM: department = models.ForeignKey(Department, on_delete=models.CASCADE). As you can see, this makes reading the code much simpler: self.course.Department_id is a Department object not an integer, so self.course.department makes more sense.
Don't prefix your field names with the class, it just makes the code so much less readable: Do you prefer department.name or department.Department_name?
The View model is still a mystery to me, as you can search without it. You can search for example for courses with a matching department name like this:
Course.objects.filter(department__name__icontains="maths")
which will return all courses with "maths" in their department name.
Remove all the ids from your models, they are created automatically by Django anyway (and called id). Again, department.id is much easier to read than department.Department_id. Also in your code, you have to generate the ids yourself since you don't set them to auto-populate.

What is different between django foreigin key in string and without string?

I am not getting why people write foreign key in two way and what is the purpose of this? are they both same or any different?
I notice some people write like:
author = models.ForeignKey(Author, on_delete=models.CASCADE)
and some people write it like:
author = models.ForeignKey('Author', on_delete=models.CASCADE)
What is different between these? is there any special purpose of writing like this or they both are same?
What is different between these? is there any special purpose of writing like this or they both are same?
They both result in the same link yes. The string will later be "resolved", and eventually the ForeignKey will point to the Author model.
Using strings however is sometimes the only way to make references however, if the models to which you target need to be defined yet. For example in the case of a cyclic reference.
Imagine for example that you define relations like:
class Author(models.Model):
name = models.CharField(max_length=128)
favorite_book = models.ForeignKey(Book, null=True, on_delete=models.SET_NULL)
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
Here a Book refers to an Author, and an Author refers to a Book. But since the Book class is not constructed at the time you construct the ForeignKey, this will give a NameError.
We can not define the Author after we defined the Book, since then we refer to the Author before it is constructed (and this thus will again yield a NameError).
We can however use strings here, th avoid the circular reference, like:
class Author(models.Model):
name = models.CharField(max_length=128)
favorite_book = models.ForeignKey('Book', null=True, on_delete=models.SET_NULL)
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
By using a string, it is fine for the Python interpreter, since you do not use an identifier that is not yet defined, and Django will then, when the models are loaded, replace the strings with a reference to the corresponding model.
The documentation on a ForeignKey [Django-doc]:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model object itself (...)
If the model is defined in another app, then you can refer to it with app_name.ModelName.
Say you have laid your models out like this:
models/
__init__.py
model_a.py
model_b.py
This is a common layout when you have an app with a lot of models and you want to better organize your code. Now say ModelA has a foreign key to ModelB and ModelB has a foreign key to ModelA. You cannot have both files importing the other model because you would have a circular import.
Referencing another model by string allows you to "lazily" reference another model that it has not yet loaded, this solves the problem of having circular imports

Getting a queryset using a foreign key field in the "other side" of a foreign key relation

Forgive me if the question does not make sense, trying to teach myself django. I've been trying to search how to do this but i'm not sure if i'm using the right words in my search.
I have the following models.
class Category(models.Model):
code = models.CharField(max_length=10, unique=True)
description = models.CharField(max_length=50)
class UserGroupHeader(models.Model):
code = models.CharField(max_length=10, unique=True)
description = models.CharField(max_length=50)
class UserGroupDetail(models.Model):
usergroupheader = models.ForeignKey(UserGroupHeader, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
How do i get a query set from the Category model using the UserGroupHeader? so far what i've got is something like this UserGroupHeader.objects.get(pk=9).usergroupdetail_set.all(), now from the result of this how do i get the Category model?
I'm not sure if I understood exactly what you are trying to do, but in general, while querying, you can follow relations using double underscores. Below are a couple of possible queries:
my_group_header = UserGroupHeader.objects.get(...)
Category.objects.filter(usergroupdetail__usergroupheader=my_group_header) # Gets Category objects related to my_group_header through UserGroupDetail model
Category.objects.filter(usergroupdetail__usergroupheader__code='abc') # Gets Category objects related to UserGroupHeader object with code 'abc' through UserGroupDetail model
UserGroupHeader.objects.filter(usergroupdetail__category__code='abc') # Gets UserGroupHeader objects related to Category object with code 'abc' through UserGroupDetail model
Your query UserGroupHeader.objects.get(pk=9).usergroupdetail_set.all() would return a QuerySet of UserGroupDetail objects. In order to get the category of each UserGroupDetail, you can:
for user_group_detail in UserGroupHeader.objects.get(pk=9).usergroupdetail_set.all():
category = user_group_detail.category
print(category. description)
Or something similar according to your needs

Getting all unique values stored in a many-to-many field

I have a many-to-many field called categories and I would like to get distinct values stored in that field.
The following is my model:
class Book (models.Model):
categories=models.ManyToManyField(Category, related_name = 'categories', blank = True, null=True)
Here is my Category model:
class Category (MPTTModel):
category = models.CharField(max_length=250)
parent = TreeForeignKey('self', blank=True, null=True, related_name='children')
I'd like to get every single one of the categories related to a book. How would I do this?
If you want to get categories related to one instance of book, do book_inst.category_set.all(). There will not be duplicates.
But I think, you want to get all Categories which are related to any Book, you can do:
Category.objects.filter(categories__in=[Book.objects.all()]).distinct()
Basically, you need a reverse lookup from the category side to check if there is book for that category if yes, add to the resultant query set. Since, the related_name argument in the Book is 'categories', your reverse lookup would look something like this.
Category.objects.filter(categories__in = Book.objects.all())