10

This is my simple Django database model. It's for a 5-star rating system.

class Rating(models.Model):
    content = models.OneToOneField(Content, primary_key=True)
    ip =  models.CharField(max_length=200, blank=True)
    rating = models.IntegerField(default=0)

As you can see, it is linked to "Content", which is the table for my documents. My question is:

  • How do I make content+ip unique...so that it multiple content is okay, but multiple content AND IP is not okay (do not want the user to rate twice).
  • How do I create a data-base index for content and ip...because I will always be selecting those (to compare if it is already in the database).
TIMEX
  • 259,804
  • 351
  • 777
  • 1,080

5 Answers5

14

Regarding your first question: You should look at unique_together, since this could solve your issue.

class Rating(models.Model):
    content = models.OneToOneField(Content, primary_key=True)
    ip =  models.CharField(max_length=200, blank=True)
    rating = models.IntegerField(default=0)

    class Meta:
        unique_together= (('content', 'ip'),)
JackDev
  • 4,891
  • 1
  • 39
  • 48
ikkebr
  • 791
  • 4
  • 11
  • 2
    it might be better to convert the IP into an `int` before storing, and use an `IntegerField`. it will use less space (im not sure why you've allocated 200 bytes to an IP address), and allow more query flexibility. you may also want to check out `django-ratings` (http://github.com/dcramer/django-ratings), which handles both anonymous and authenticated votes very well. – Carson Nov 26 '09 at 17:48
7

BTW, if, as it appears from your terminology, you're using IP addresses as standing for users' identities, please don't -- it's a seriously horrible idea. Users coming in through their ISP will get their IPs changed at random times, so they might vote twice; users on a laptop connecting at various coffee shops, libraries, &c, will have always-varying IPs; users sharing a connection (e.g., apartment-mates), or even every single one of users coming in from a University campus, might get the same IP address via NAT, so only one will be able to vote... it's hard to think of any worse way to represent individuals' identities!-)

If your use of the name ip for your "user identity" field is accidental and has nothing to do with using IP addresses there, I apologize, but in that case please do rename that field!-)

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
5

About the indexes: you don't need to do anything for content, since it is a primary key, it will be indexed. For ip, just add db_index=True to the CharField constructor call:

ip = models.CharField(max_length=200, blank=True, db_index=True)

More information about db_index and other field options here

Akseli Palén
  • 27,244
  • 10
  • 65
  • 75
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
4

This is the answer for those who are using Django 3.0+.

It's better to use UniqueConstraint ( as per the docs ) for making uniques.

 class Rating(models.Model):
    ...

    class Meta:
        constraints = [ models.UniqueConstraint(fields=['content', 'ip'], name="unique-content-ip") ]
        indexes = [ models.Index(fields=['content', 'ip']) ]

And hence you can define multiple constraints & indexes.

adshin21
  • 178
  • 2
  • 9
0

Please try this metha keyword: "unique_together"

    class PowerBoardSwitches(models.Model):
        id = models.AutoField(primary_key=True, verbose_name='Switch id')
        powerBoardId = models.ForeignKey(PowerBoardDevice, models.DO_NOTHING, db_column='powerBoardId', verbose_name='Power Board Id')
        powerBoardSwitchId = models.IntegerField()
        powerBoardSwitchStatus = models.IntegerField()
        createdOn = models.DateTimeField(auto_now_add=True, verbose_name='Created on date')
        updatedOn = models.DateTimeField(auto_now_add=True, verbose_name='Updated on date')

        class Meta:
            unique_together = (('powerBoardId', 'powerBoardSwitchId'), )
Ashish Gupta
  • 1,153
  • 12
  • 14