2π
β
You should either go with a through field like this:
class Story(models.Model):
rates = models.ManyToManyField(User, through=Rating)
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
or you can do it your way with a separate model which in this case your either should remove the rate
field from Story
model or remove the story
field from Rating
model:
class Story(models.Model):
...
# rate = models.(help here) No need anymore
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
and your queryset will be something like this:
story.rating_set.all()
Which will include all the ratings for the selected story instance.
π€Navid Zarepak
4π
As @Liudvikas Bajarunas said, itβs enough to define story
as a foreign key on the Rating
model. You can access the story ratings using rating_set
:
story_ratings = story.rating_set.all()
See the documentation on following relationships backwards for more info.
You can combine that approach with aggregation to get the average rating of a story:
class Story(models.Model):
...
@property
def average_rating(self):
return self.rating_set.all().aggregate(Avg('rate'))['rate__avg']
π€Pierre V.
- [Django]-ManyToMany in Django admin: select none
- [Django]-Setting number of gunicorn workers in django settings.py
- [Django]-Django rest framework custom return response
- [Django]-How to make a model instance read-only after saving it once?
- [Django]-Django objects being "non subscriptable" leads me to write redundant code
4π
There are some improvements that you can make:
- It is better to refer to the user model with the
AUTH_USER_MODEL
setting [Django-doc] to refer to the user model, since you can later change your mind about it; - You probably want to make
user
andstory
unique together, such that a user can not make two ratings for the same story; - some databases, like PostgreSQL allow us to enforce range constraints at the database level, and thus make it more safe.
we thus can rewrite this to:
from django.conf import settings
from django.db import models
from django.db.models import CheckConstraint, Q, UniqueConstraint
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Meta:
constraints = [
CheckConstraint(check=Q(rate__range=(0, 10)), name='valid_rate'),
UniqueConstraint(fields=['user', 'story'], name='rating_once')
]
- [Django]-Using Django's memcache API on Dynamically created models
- [Django]-Error when creating admin in django tutorial
- [Django]-Celery 4.0.0 and Class based task workflow
Source:stackexchange.com