Alex Zaitsev
Alex Zaitsev

Reputation: 1781

Django ORM relations one-to-many

I have a model:

class Product(models.Model):
    title = models.CharField(max_length=200)
    url = models.URLField()
    pub_date = models.DateTimeField()
    votes_total = models.IntegerField(default=1)
    image = models.ImageField(upload_to='images/')
    icon = models.ImageField(upload_to='images/')
    body = models.TextField()
    hunter = models.ForeignKey(User, on_delete=models.CASCADE)

Now I'd like to add a functionality of upvoters to know on what products user has already voted. I need this to allow users vote on the one product only once.
Again, to clarify - user can vote on several products but only once on each.
So the relation is one product - many users (upvoters).
I tried to add the next field but cannot make a migration even if default field is provided. Also I tried to clear the database but again cannot make it work.

upvoters = models.ForeignKey(User, on_delete=models.CASCADE, related_name='upvoted')

I suppose it works the next way:

Field to determine upvoted products. To check if user has been upvoted on product, call: User.upvoted.filter(id=product.id).count() == 1 This means that user has already upvoted on this product.

What's wrong? What should I change to make it work?

Upvotes: 0

Views: 108

Answers (1)

Shane
Shane

Reputation: 653

You will have to use ManyToMany, but you can use a custom through model to restrict the product/vote combinations.

To Product class, add:

voters = models.ManyToManyField(User, through='ProductVote', related_name='product_voters')

Then add the custom through model:

class ProductVote(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    product = models.ForeignKey(Vote, on_delete=models.CASCADE)

    class Meta:
        unique_together = ['user', 'product']

If you try to add a vote for the same user/product combination, an IntegrityError will be raised.

Upvotes: 4

Related Questions