I am trying to add OneToMany field in django rest models. But Django is not giving an options for it. Can anyone suggest something similar to java #OneToMany in Django framework
You can use related_name in ForeignKey field to achieve this.
For example, you have the following models:
class Author(models.Model):
name = models.CharField(max_length=128)
class Book(models.Model):
name = models.CharField(max_length=128)
author = models.ForeignKey(Author, related_name='books', on_delete=models.CASCADE)
Now, to access all books of an author the query will be Author.books.all(). Here, notice that Author model don't have books attribute. But in author ForeignKey field (which refers the Author model) of Book model has the related_name argument and its value is books. It means that books of an auhtor can be accessed from Author model. Django handles it nicely.
Also, you can use select_related for optimization (in this case you don't need to use related_name argument): Book.objects.all().select_related('author')
Related
My models.py:
class Author(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(
"Book", related_name="books", blank=True
)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ManyToManyField(Author)
In Django admin I first created an instance of Author, without assigning him any Book:
Then I created a new Book and assigned Leo Tolstoy as theAuthor:
In Django shell, I am able to access the Book's Author:
>>> Book.objects.filter(title="War and Peace").first().author.first()
<Author: Leo Tolstoy>
But I'm unable to access the Author's Books:
>>> Author.objects.filter(name="Leo Tolstoy").first().books.all()
<QuerySet []>
The book isn't assigned in the Admin view either:
I would like to access the Author's Books as well as for the Books
to show in the Author's Admin view.
You only need one ManyToManyField. You should also pass "books" as the related_name on Book.authors as this is the name Django will use for the many-to-many manager attribute it automatically adds to Author instances.
See the example in the Django docs for more info.
When a ManyToManyField is created on both sides of a relation, Django is creating two associative tables between the book and author tables under the hood. Changes to one table don't affect the other.
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(
Author, related_name="books", blank=True
)
I suggest you do this:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ManyToManyField(Author, related_name="books",blank=True)
You need one ManyToManyField, then django will create two associative tables between the book and author tables. Changes to one table will not affect the other. You can see in the django documentation about many to many relationships. I have removed your books field in my answer because you have created an instance of your Author but you did not assign his 'book' and you have created a Book instance with giving title and author in your Book model. So so that any of your data won't be deleted. I also added related_name to your author field in your Book model because when you try to get the books related to the author (for example "Loe Tolstoy") you can get by this:
Author.objects.get(name="Leo Tolstoy").books.all()
Given these models:
class Event(models.Model):
name = models.CharField()
class Project(models.Model):
name = models.CharField()
class EventProject(models.Model):
event= models.ForeignKey(Event)
project= models.ForeignKey(Project)
Is there a way to get all the Events for each Project like this: with the property project.events = [<array of Event>]?
I found a similar question, however one of the tables has the members = models.ManyToManyField(Person, through='Membership') relationship so it's easier to do. I can't do as in the related question and add a relationship as I cannot change the model.
It is straight Forward
Event.objects.filter(eventproject__project=project)
Filtering through ForeignKey works both forward and backward in Django. You can use the model name in lower case for backward filtering.
https://docs.djangoproject.com/en/3.1/topics/db/queries/#lookups-that-span-relationships
The django documentation is pretty clear on how to look up fields on single instances but what about reverse relationship QuerySet objects.
Example:
class Author(models.Model)
name = models.Charfield(...)
class Book(models.Model)
title = models.Charfield(...)
author = models.ForeignKey(Author, ...)
I now create a queryset object:
special_books = Book.objects.filter(title__icontains="Space")
Now, I want to find all authors that belong to special_books. I want to do something like this:
special_books.authors.all()
Without doing this:
authors = []
for book in special_books:
authors += book.author
Is there a way to do this easily?
Use the referenced Model name (Book in lowercase) to make your query:
Author.objects.filter(book__title__icontains="Space")
If you have a related_name defined in your foreignKey :
class Book(models.Model)
title = models.Charfield(...)
author = models.ForeignKey(Author, related_name="books")
Your queryset would be :
Author.objects.filter(books__title__icontains="Space")
Quoting Django's documentation :
Related managers support field lookups as well. The API automatically follows relationships as far as you need. Use double underscores to separate relationships. This works as many levels deep as you want.
Simply do the lookup on Author model that spans relationship
Author.objects.filter(book__title__icontains="Space")
i have an issue with the code in django framework regarding to related_name and related_query_name in django. please django expert explain the related_name in django, the code is below:
related_name='+'
Related Name
Django maintains backward relation on each object for easy access to related objects. Suppose you have two models named "School" and "Student" and one school can have multiple students. So you will have model definition something like this
class School(models.Model):
name = models.CharField(max_length=55)
city = models.Charfield(max_length=55)
class Student(models.Model):
name = models.CharField(max_length=55)
school = models.ForeignKey(School)
Now if you have an school objects then you can access all students of that school with writing query explictly.
school = School.objects.get(id=1)
# Now if need all students of this school, first thing that come in your mind would be
Student.objects.filter(school=school)
# But instead of this, you can access all students by
school.student_set.all()
Here student_set is the default, related name made by Django. But you can have your custom related names like this
class Student(models.Model):
name = models.CharField(max_length=55)
school = models.ForeignKey(School, related_name='students')
# Now you can do
school.students.all()
Special Character in related name
If you define related_name='+' then backward relation would not be available on object and school.student_set.all() will give you error.
If you’d prefer Django not to create a backwards relation, set related_name to '+' or end it with '+'. For example, this will ensure that the User model won’t have a backwards relation to this model:
Related Query Name
related_query_name is similar to related_name but it gets used in queryset.
If you need to apply some filter on student via school model, then you would do
School.objects.filter(student__name='abc')
But if you define related_query_name then you can do
class Student(models.Model):
name = models.CharField(max_length=55)
school = models.ForeignKey(School, related_query_name='abc')
# Now you can do
School.objects.filter(abc__name='abc')
Refer doc for further reference: https://docs.djangoproject.com/en/3.0/ref/models/fields/
I have the following models:
class Reputation(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
score = models.IntegerField(default=0)
....
class Article(models.Model):
created_by = models.ForeignKey(settings.AUTH_USER_MODEL)
....
I am trying to access the "score" field on the Reputation model from an Article object. I tried the following on an Article object (article_object), but it does not work:
article_object.created_by.reputation_set.score
Is there any way I can access "score" from an Article object? Thank you.
Use article_object.created_by.reputation.score instead.
OneToOneField auto creates a backward reference with the name of the model in lowercase.
You can override the related object name by setting related_name on the field.
Sources
One-to-one relationships
ForeignKey.related_name