django models hierarchy question: related attributes of a ManyToManyField - django

As a fresh coder, I seriously have problems to build my models relations.
Please check these two cases, How can I set current_reading_pages on my Scenario2?
from django.db import models
# Scenario1: Users can record their reading progress of a book.
class Book(models.Model):
name = models.CharField(max_length=128)
class User(models.Model):
current_reading_book = models.ForeignKey('Book', on_delete=models.CASCADE)
current_reading_page = models.IntegerField()
Result1: No problems about database, but Users can records their progress of only one book.
Other scenario, which I want to build:
from django.db import models
# Scenario2: Users can record their reading progress of multiple books.
class Book(models.Model):
name = models.CharField(max_length=128)
class User(models.Model):
current_reading_books = models.ManyToManyField('Book')
# current_reading_pages = ???
I want to save all progress of current books, for example,
User A is reading 3 books, book1 till page 100, book2 till page 10, book3 till page 0.
And I found 'through' parameter in django ManyToManyField,
My codes become like below but it does not work as I expected.
from django.db import models
# Scenario3: Using through parameter in ManyToManyField
class Book(models.Model):
name = models.CharField(max_length=128)
class User(models.Model):
current_reading_books = models.ManyToManyField('Book', through='ReadingBook')
class ReadingBook(models.Model):
book = models.ForeignKey('Book', on_delete=models.CASCADE)
current_reading_page = models.IntegerField()
ERRORS:
test_model.ReadingBook: (fields.E336) The model is used as an intermediate model by 'test_model.User.current_reading_books', but it does not have a foreign key to 'User' or 'Book'.

I think, that first scenario is easy to realize.
just add user attribute into the custom class UserBook
for example
class UserBooks(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
current_page = models.IntegerField(default=1)
if user wanna check his progress, in views.py you can just filter by books = UserBooks.objects.filter(user=request.user)

Related

Django error with models (ManyToManyField)

I was building my app using django but I got this error in the models.py file:
creator = models.ManyToManyField(Teacher, on_delete=models.CASCADE)
NameError: name 'Teacher' is not defined
This is my current code in models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class School(models.Model):
nombre = models.CharField(max_length=355)
profesoras = models.ManyToManyField(Teacher)
class Teacher(models.Model):
user = models.ForeignKey(User, related_name="teacherClass", blank=False)
school = models.ManyToManyField(School, blank=True)
class Post(models.Model):
creator = models.ManyToManyField(Teacher, on_delete=models.CASCADE)
title = models.CharField(max_length=255)
text = models.TextField(max_length=2000)
Do you know how can I solve this error?
The issue here is that you are trying to reference a model that has not been created yet. The Django docs state what to do in such a case.
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:
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
So for your case, you would just change your model relationships to strings.
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class School(models.Model):
nombre = models.CharField(max_length=355)
profesoras = models.ManyToManyField("Teacher") # Make this a string because it has not been defined yet
class Teacher(models.Model):
user = models.ForeignKey(User, related_name="teacherClass", blank=False)
school = models.ManyToManyField(School, blank=True)
class Post(models.Model):
creator = models.ManyToManyField("Teacher", on_delete=models.CASCADE) # Same with this one.
title = models.CharField(max_length=255)
text = models.TextField(max_length=2000)
The django docs are always really useful and have a lot of good information.
The error is just fine because you are using it before declaring it and also your relationships are a little messy. You can say that you can have as many schools as you wish in this app and each professor teaches in many schools so it can be something like this by using many to many relation:
class School(models.Model):
name = models.CharField(max_length=355)
class Teacher(models.Model):
user = models.ForeignKey(User, related_name="teacherClass", blank=False, on_delete=models.CASCADE)
school = models.ManyToManyField(School, blank=True)
class Post(models.Model):
creator = models.ManyToManyField(Teacher)
title = models.CharField(max_length=255)
text = models.TextField(max_length=2000)
I suggest you that study a little bit about relations in databases so you won't have any similar problem in future.

Setting a Django ForeignKey to multiple models

I have a simple model called WebProfile that stores a webpage URL and its title. This model has a ForeignKey to a Student model, which allows me to store the student's bookmarks.
I would like to reuse this model to also store bookmarks saved by teachers. What is the best way to have the owner ForeignKey point to either a Student or Teacher?
Note: in my actual use case, the target model classes are conceptually very different and do not share any common fields other than the WebProfile links.
class Student(models.Model):
...
class Teacher(models.Model):
...
class WebProfile(models.Model):
title = models.CharField(max_length=50)
link = models.URLField()
owner = models.ForeignKey('Student', on_delete=models.CASCADE, related_name="bookmarks")
If Teacher and Student are related to the User model you could change the ForeignKey in WebProfile to be related to the User model instead.
From there you can then workout when you get a WebProfile object whether the user is a Student or Teacher.
I was able to solve the problem by using Generic Relations as described in Django documentation
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class WebProfile(models.Model):
title = models.CharField(max_length=50)
link = models.URLField()
owner_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
owner_id = models.PositiveIntegerField()
owner = GenericForeignKey('owner_type', 'owner_id')

Django ORM - model referencing another models ManyToMany field

I'm currently trying to setup some database models in djangos ORM. however im unable to figure out how i'm supposed to reference another models many-to-many- field.
Project model
class Project(models.Model):
projectName = models.CharField(max_length=200)
users = models.ManyToManyField(get_user_model())
projectOwner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='projectowner', default=1)
The users = models.manytomanyfield(get_user_mode()) works fine
and generates the correct relation in the database.
now i want to add a new model that adds a many to many relation between rights and project_user
so what the end result tables are supposed to look like:
project:
projectname - string
projectowner - id of referenced user
user: django orm auth user model
rights:
name
description
etc
project_user:
id
project_id
user_id
rights_projectuser:
id
rights_id
project_user_id
now that last one (rights_projectuser) is what i dont know how to make.
You need to turn "project_user" into a through model that you can then add the many to many relationship to.
class Project(models.Model):
projectName = models.CharField(max_length=200)
users = models.ManyToManyField(get_user_model(), through='ProjectUser')
class ProjectUser(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
rights = models.ManyToManyField(Right)
i now get the following problem when running this code:
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Project(models.Model):
projectName = models.CharField(max_length=200)
users = models.ManyToManyField(get_user_model(), through='ProjectUser')
projectOwner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='projectowner', default=1)
class Right(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
class ProjectUser(models.Model):
user_id = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
project_id = models.ForeignKey(Project, on_delete=models.CASCADE)
rights = models.ManyToManyField(Right)
ValueError: Cannot alter field wspingpong.Project.users into wspingpong.Project.users - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)

What is the process that you follow to create model in Django?

What is the process that you follow to create model in Django? Thanks.
The most important part of a model – and the only required part of a model – is the list of database fields it defines. Fields are specified by class attributes. Be careful not to choose field names that conflict with the models API like clean, save, or delete.
Models.py
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
You can start here Documentation
See also Django Girls Models

Django models asymmetric relationship

With following Django models:
class Author(models.Model):
name = models.CharField(max_length=30)
bestbookaccordingtome=models.????(Author,null=True, blank=True, default = None)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.OnetoOneField(Author)
I want the classic relationship each book has one author (only).
But I also want to be able to assign a chosen book to author (my favourite book of this author for example).
I tried a foreign key but django didn't like it.
Any python clean way to do it?
What you need is ManyToManyField.
class Author(models.Model):
name = models.CharField(max_length=30)
bestbookaccordingtome = models.ManyToManyField('self', symmetrical=False, related_name='best_book_according_to_me')
Also, if you need to specify extra fields in your n-m model, you can use through to indicate the name of the model.
Hope it helps!