<commit_before>from django.db import models

import forms

# The following code is based on the FuzzyDate snippet
# http://blog.elsdoerfer.name/2008/01/08/fuzzydates-or-one-django-model-field-multiple-database-columns/

class Rating(object):
    def __init__(self, score, votes):
        self.score = score
        self.votes = votes
    
    def add(self, **kwargs):
        # TODO
        pass

class RatingCreator(object):
    def __init__(self, field):
        self.field = field
        self.votes_field_name = "%s_votes" % (self.field.name,)
        self.score_field_name = "%s_score" % (self.field.name,)

    def __get__(self, obj, type=None):
        if obj is None:
            raise AttributeError('Can only be accessed via an instance.')

        score = obj.__dict__[self.score_field_name]
        if score is None: return None
        else:
            return Rating(score=score, votes=getattr(obj, self.votes_field_name))

    def __set__(self, obj, value):
        if isinstance(value, Rating):
            setattr(obj, self.votes_field_name, value.votes)
            setattr(obj, self.score_field_name, value.score)
        else:
            raise TypeError("%s value must be a Rating instance, not '%r'" % (self.field.name, value))

class RatingField(models.IntegerField):
    """
    A rating field contributes two columns to the model instead of the standard single column.
    """
    allow_anonymous = False
    
    def __init__(self, **kwargs):
        if 'choices' not in kwargs:
            raise TypeError("%s missing required attribute 'choices'" % (self.__class__.__name__,))
        super(RatingField, self).__init__(verbose_name, name, **kwargs)
    
    def contribute_to_class(self, cls, name):
        # Votes tally field
        votes_field = models.PositiveIntegerField(
            editable=False, default=0)
        votes_field.creation_counter = self.creation_counter
        cls.add_to_class"%_votes" % (name,), votes_field)

        # Score sum field
        score_field = models.IntegerField(
            editable=False, default=0)
        score_field.creation_counter = self.creation_counter
        cls.add_to_class("%_score" % (name,), score_field)

        setattr(cls, self.name, RatingCreator(self))

    def get_db_prep_save(self, value):
        # XXX: what happens here?
        pass

    def get_db_prep_lookup(self, lookup_type, value):
        # TODO: hack in support for __score and __votes
        raise NotImplementedError, self.get_db_prep_lookup
        if lookup_type == 'exact':
            return [self.get_db_prep_save(value)]<commit_msg>added RatingManager object; refactored a bit of the logic; added RatingManager.add method called via myinstance.myfield.add()<commit_after>from django.db import models
from django.contrib.contenttypes.models import ContentType

from django.conf import settings

from models import Vote, Score

import forms

if 'django.contrib.contenttypes' not in settings.INSTALLED_APPS:
    raise ImportError("djangoratings requires django.contrib.contenttypes in your INSTALLED_APPS")

# The following code is based on the FuzzyDate snippet
# http://blog.elsdoerfer.name/2008/01/08/fuzzydates-or-one-django-model-field-multiple-database-columns/

class Rating(object):
    def __init__(self, score, votes):
        self.score = score
        self.votes = votes

class RatingManager(object):
    def __init__(self, instance, field, score, votes):
        self.score = score
        self.votes = votes
        self.instance = instance
        self.field = field
        
    def add(self, score, user, ip_address):
        if score not in self.field.choices:
            raise ValueError("%s is not a valid choice for %s" % (score, self.field.name))
        is_anonymous = (request.user is None or not request.user.is_authenticated())
        if is_anonymous and not self.field.allow_anonymous:
            raise TypeError("%s is not a valid option for %s" % (user, self.field.name))
        
        defaults = dict(
            score = score,
            ip_address = ip_address,
            user = is_anonymous and None or user,
        )
        
        if is_anonymous:
            rating, created = Vote.objects.get_or_create(
                content_type    = self.field.get_content_type(),
                object_id       = self.instance.id,
                ip_addresss     = ip_address,
                defaults        = defaults,
            )
        else:
            rating, created = Vote.objects.get_or_create(
                content_type    = self.field.get_content_type(),
                object_id       = self.instance.id,
                user            = user,
                defaults        = defaults,
            )
        if not created and self.field.can_change_vote:
            rating.score = score
            rating.save()
            

class RatingCreator(object):
    def __init__(self, field):
        self.field = field
        self.votes_field_name = "%s_votes" % (self.field.name,)
        self.score_field_name = "%s_score" % (self.field.name,)
        self.content_type = None

    def __get__(self, instance, type=None):
        if instance is None:
            raise AttributeError('Can only be accessed via an instance.')

        return RatingManager(instance, field, score=getattr(instance, self.score_field_name), votes=getattr(instance, self.votes_field_name))

    def __set__(self, instance, value):
        if isinstance(value, Rating):
            setattr(instance, self.votes_field_name, value.votes)
            setattr(instance, self.score_field_name, value.score)
        else:
            raise TypeError("%s value must be a Rating instance, not '%r'" % (self.field.name, value))

    def get_content_type(self):
        if self.content_type is None:
            self.content_type = ContentType.objects.get_for_model(self.instance,)
        return self.content_type

class RatingField(models.IntegerField):
    """
    A rating field contributes two columns to the model instead of the standard single column.
    """
    allow_anonymous = False
    
    def __init__(self, **kwargs):
        if 'choices' not in kwargs:
            raise TypeError("%s missing required attribute 'choices'" % (self.__class__.__name__,))
        self.can_change_vote = kwargs.pop('can_change_vote', False)
        super(RatingField, self).__init__(verbose_name, name, **kwargs)
    
    def contribute_to_class(self, cls, name):
        # Votes tally field
        votes_field = models.PositiveIntegerField(
            editable=False, default=0)
        votes_field.creation_counter = self.creation_counter
        cls.add_to_class"%_votes" % (name,), votes_field)

        # Score sum field
        score_field = models.IntegerField(
            editable=False, default=0)
        score_field.creation_counter = self.creation_counter
        cls.add_to_class("%_score" % (name,), score_field)

        setattr(cls, self.name, RatingCreator(self))

    def get_db_prep_save(self, value):
        # XXX: what happens here?
        pass

    def get_db_prep_lookup(self, lookup_type, value):
        # TODO: hack in support for __score and __votes
        raise NotImplementedError, self.get_db_prep_lookup
        if lookup_type == 'exact':
            return [self.get_db_prep_save(value)]
{'fraction_non_alphanumeric': 0.09417714598141061, 'fraction_numerical': 0.002733734281027884, 'mean_word_length': 2.536491058482359, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7454402', 'n_tokens_mistral': 2155, 'n_tokens_neox': 2092, 'n_words': 539}