English 中文(简体)
Custom save method giving invalid tuple size error
原标题:

I ve been stuck on this likely very simple problem, but haven t gotten anywhere with it (newbie to Python and Django). I m taking some user submitted data and using weights to calculate a score. Despite my best efforts, I m getting the following when I submit the data via a form: "global name appearance is not defined". I m pretty sure my issue is in views.py, but I m not 100% sure. Either a typecast error or just putting the calculation of the score in the wrong place. Any help is much appreciated. Here s my code:

Update: The error I m receiving after changing my approach to using a custom save method is: "Invalid tuple size in creation of Decimal from list or tuple. The list or tuple should have exactly three elements.".

models.py

# Beer rating weights
APPEARANCE_WEIGHT = 0.15
AROMA_WEIGHT = 0.15
MOUTHFEEL_WEIGHT = 0.10
TASTE_WEIGHT = 0.25
TOTALPACKAGE_WEIGHT = 0.25

SERVING_TYPE = (
( 0 ,  Choose One ),
( Draft ,  Draft ),
( Bottle ,  Bottle ),
( Can ,  Can ),
)
SCORING = (
(0,   ),
(1,  1 ),
(2,  2 ),
(3,  3 ),
(4,  4 ),
(5,  5 ),
(6,  6 ),
(7,  7 ),
(8,  8 ),
(9,  9 ),
(10,  10 ),
)
class Beerrating(models.Model):
beerrated = models.ForeignKey(Beer)
user = models.ForeignKey(User)
date = models.DateTimeField(auto_now_add=True)
servingtype = models.CharField(max_length=10, choices=SERVING_TYPE)
appearance = models.IntegerField(choices=SCORING, default=0)
aroma = models.IntegerField(choices=SCORING, default=0)
mouthfeel = models.IntegerField(choices=SCORING, default=0)
taste = models.IntegerField(choices=SCORING, default=0)
totalpackage = models.IntegerField(choices=SCORING, default=0)
comments = models.TextField()
overallrating = models.DecimalField(max_digits=4, decimal_places=2)

def __unicode__(self):
    return u %s, %s  % (self.user.username, self.beerrated.beername)

def save(self):
    if not self.id:
        scoredappearance = self.appearance * APPEARANCE_WEIGHT,
        scoredaroma = self.aroma * AROMA_WEIGHT,
        scoredmouthfeel = self.mouthfeel * MOUTHFEEL_WEIGHT,
        scoredtaste = self.taste * TASTE_WEIGHT,
        scoredtotalpackage = self.totalpackage * TOTALPACKAGE_WEIGHT,
        self.overallrating = (scoredappearance +    scoredaroma + 
            scoredmouthfeel + scoredtaste + scoredtotalpackage)
        super(Beerrating, self).save()

forms.py

class BeerReviewForm(ModelForm):
servingtype = forms.CharField(max_length=10,
    label=u Serving Type ,
    widget=forms.Select(choices=SERVING_TYPE)
)
totalpackage = forms.IntegerField(
    label=u Total Package ,
    widget=forms.Select(choices=SCORING)
)
class Meta:
    model = Beerrating
    exclude = ( beerrated ,  user ,  date ,  overallrating )

views.py

def beerreview(request, beer_id):
beer = get_object_or_404(Beer, id=beer_id)
if request.method ==  POST :
    form = BeerReviewForm(request.POST)
    if form.is_valid():
        # Create review
        beerrating = Beerrating(
            beerrated = beer,
            user = request.user,
            servingtype = form.cleaned_data[ servingtype ],
            appearance = form.cleaned_data[ appearance ],
            scoredappearance = appearance * APPEARANCE_WEIGHT,
            aroma = form.cleaned_data[ aroma ],
            scoredaroma = aroma * AROMA_WEIGHT,
            mouthfeel = form.cleaned_data[ mouthfeel ],
            scoredmouthfeel = mouthfeel * MOUTHFEEL_WEIGHT,
            taste = form.cleaned_data[ taste ],
            scoredtaste = taste * TASTE_WEIGHT,
            totalpackage = form.cleaned_data[ totalpackage ],
            scoredtotalpackage = totalpackage * TOTALPACKAGE_WEIGHT,
            comments = form.cleaned_data[ comments ],
        )
        beerrating.save()
        return HttpResponseRedirect( /beers/ )
else:
    form = BeerReviewForm()
variables = RequestContext(request, {
     form : form
})
return render_to_response( beer_review.html , variables)
最佳回答

In your save method, the lines:

scoredappearance = self.appearance * APPEARANCE_WEIGHT,
...

are all assigning a tuple, not the number you expect, to the variables. A tuple is basically an immutable list. The training comma on all those lines makes them tuples. What you want is:

scoredappearance = self.appearance * APPEARANCE_WEIGHT
...

Two other problems with your save function. First, because of your indentation, your super only gets called on an update -- which means you ll never be able to create this object!

Secondly, I d recommend adding the variable arg lists to your save function. This means if it gets called with parameters, they get transparently passed onto the super.

Here s the rewritten function:

def save(self,*args,**kwargs):
    if not self.id:
            scoredappearance = self.appearance * APPEARANCE_WEIGHT
            scoredaroma = self.aroma * AROMA_WEIGHT
            scoredmouthfeel = self.mouthfeel * MOUTHFEEL_WEIGHT
            scoredtaste = self.taste * TASTE_WEIGHT
            scoredtotalpackage = self.totalpackage * TOTALPACKAGE_WEIGHT
            self.overallrating = (scoredappearance +        scoredaroma + 
                    scoredmouthfeel + scoredtaste + scoredtotalpackage)

    super(Beerrating, self).save(*args,**kwargs)

As a final note -- and if you ve already done this, I apologize -- I d really recommending working through a book like Learning Python. Python s a generally straightforward language -- but it has some subtle features (like tuples and variable argument lists) that will cause you trouble if you don t understand them.

问题回答

The error message should specifically tell you the file and line number of the error, but your problem are these two lines in your views.py:

appearance = form.cleaned_data[ appearance ],
scoredappearance = appearance * APPEARANCE_WEIGHT,

You are assuming the Python interpreter computes the value for appearance before you use it in the next argument... which is an incorrect assumption.

Define appearance before you create the model instance and your code should then work (or at least break on a different error).





相关问题
How to get two random records with Django

How do I get two distinct random records using Django? I ve seen questions about how to get one but I need to get two random records and they must differ.

Moving (very old) Zope/Plone Site to Django

I am ask to move data from a (now offline) site driven by Plone to a new Django site. These are the version informations I have: Zope Version (unreleased version, python 2.1.3 ) Python Version 2.1....

Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

Flexible pagination in Django

I d like to implement pagination such that I can allow the user to choose the number of records per page such as 10, 25, 50 etc. How should I go about this? Is there an app I can add onto my project ...

is it convenient to urlencode all next parameters? - django

While writing code, it is pretty common to request a page with an appended "next" query string argument. For instance, in the following template code next points back to the page the user is on: &...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

热门标签