Django querysets indexes - django

I was wondering if using indexes on a model was possible:
class Buildings(models.Model):
island = models.ForeignKey(Island)
townhall = models.IntegerField(default=1)
lumberjack = models.IntegerField(default=0)
stonequarry = models.IntegerField(default=0)
ironmine = models.IntegerField(default=0)
[...]
a=Buildings.objects.get(somecondition)
print a.townhall # 1
a[1] +=1
print a.townhall # 2
Currently it throws
"TypeError: 'Buildings' object is
unindexable"
The reason why I'd like to do something like this is that using indexes would simplify parts of code like this:
if queue.kind_id == 0: buildings.townhall += 1
elif queue.kind_id == 1: buildings.lumberjack += 1
elif queue.kind_id == 2: buildings.stonequarry += 1
elif queue.kind_id == 3: buildings.ironmine += 1
elif queue.kind_id == 4: buildings.factory += 1
elif queue.kind_id == 5: buildings.shipyard += 1
elif queue.kind_id == 6: buildings.university += 1
to this:
buildings[queue.kind_id] +=1

The get() method doesn't return a queryset, only a single instance/object of the model class. If you want want to retrieve more than one object (=a queryset) use filter() instead!
a=Buildings.objects.filter(...)
I am not sure what you are trying to use the lumberjack, townhall etc attributes for...
I think you could do something like:
buildings_list = ['townhall', 'lumberjack', ....]
attr = buildings_list[queue.kind_id]
setattr(buildings, attr, getattr(buildings, attr) + 1)
But I am not sure what you are trying to do and if you are using django's models in the way they are inteded to be used...

Related

Dynamically add lookup field suffix to lookup field

I currently have this pretty standard code block in my views.py.
statsign is a form value, as well as statinput.
My model field I want to filter my queryset players by is called nba_avg_rating
if statsign == '>=' and len(statinput) > 0:
players = players.filter(nba_avg_rating__gte=float(statinput)).order_by(sort)
elif statsign == '<=' and len(statinput) > 0:
players = players.filter(nba_avg_rating__lte=float(statinput)).order_by(sort)
elif statsign == '=' and len(statinput) > 0:
players = players.filter(nba_avg_rating__exact=float(statinput)).order_by(sort)
As you can see, currently my logic checks the statsign for a condition, filters by model field + the suffix, i.e. >= would result in filtering by nba_avg_rating__gte, so on and so forth.
My goal is to make this a dynamic process, in which I consolidate this process into one line. I have a field lookup dictionary like so
field_lookup = {
'>=': '__gte',
'<=': '__lte',
'=': '__exact'
}
And then I iterate through, appending the suffix to the field name, in some code like below.
for item in field_lookup.items():
if statsign == item[0] and len(statinput) > 0:
players = players.filter((nba_avg_rating + item[1])=float(statinput)).orderby(sort)
Now obviously the above code doesn't work, because nba_avg_rating is an expression. I can concatenate the suffix to nba_avg_rating as a string and then wrap it in eval, but alas, I then can't set the expression =flost(statinput)
Any thoughts on what I can do here?
Thanks
According to Daniel Answer.
You can do something like:
if statsign == '>=':
statsign = 'gte'
elif statsign == '<=':
statsign = 'lte'
elif statsign == '=':
statsign = 'exact'
if len(statinput) > 0:
kwargs = {
'{0}__{1}'.format('nba_avg_rating', statsign): float(statinput),
}
Person.objects.filter(**kwargs).orderby(sort)

Django REST Framework: custom serializer variables

I am using a model serializer (many=True) in Django Rest Framework where I want to return booking_color and text_color properties in JSON in order to display a booking instance on a calendar plugin. Both properties depend on job_type and job_status variables that are calculated (using foreign keys, etc.). I want to run a calculation for those variables when a particular instance gets initialized (in the init method) so that both calculated values then become available for both method fields (booking_color and text_color). The init method, however, passes entire queryset as 'inst' and so I can't do instance-specific calculations. What would be the best way around this? I have previously ran those calculations in the first method in the list ('get_booking_color' in this case) and it works, but it isn't very elegant and I am not sure if I am supposed to do it.
class CalendarView(serializers.ModelSerializer):
booking_color = serializers.SerializerMethodField()
text_color = serializers.SerializerMethodField()
def __init__(self, inst):
self.job_type = [complicated calculation that depends on inst values]
self.invoice_status = [complicated calculation that depends on inst values]
def get_booking_color(self, inst):
if self.invoice_status == 1:
if self.job_type == 1:
return "#000000"
elif self.job_type == 2:
return "#f1c40f"
elif self.job_type == 3:
return "#FFFFF"
else:
return '#faase4'
def get_text_color(self, inst):
if self.invoice_status == 2:
if self.job_type == 1:
return "#BBFF33"
elif self.job_type == 2:
return "#272844"
elif self.job_type == 3:
return "#2c0716"
else:
return '#FFFFF'
I believe you need to modify your __init__() call to this:
def __init__(self, instance=None, data=empty, **kwargs):
self.job_type = [complicated calculation that depends on inst values]
self.invoice_status = [complicated calculation that depends on inst values]
super(CalendarViewSerializer, self).__init__(**kwargs)
I'd also recommend renaming your class to CalendarViewSerializer so it is not confused with anythign else.
You may also be able to move around overriding the __init__() call by passing in those calculations via the context - then working with them from there...e.g.,
serializer = CalendarViewSerializer(data=request.data, context={'job_type': ..., 'invoice_status': ...})
class CalendarViewSerializer(serializers.ModelSerializer):
booking_color = serializers.SerializerMethodField()
text_color = serializers.SerializerMethodField()
def get_booking_color(self, inst):
if self.context['invoice_status'] == 1:
if self.context['job_type'] == 1:
return "#000"
elif self.context['job_type'] == 2:
return "#f1c40f"
elif self.context['job_type'] == 3:
return "#fff"
else:
return '#faase4'
def get_text_color(self, inst):
if self.context['invoice_status'] == 2:
if self.context['job_type'] == 1:
return "#bbff33"
elif self.context['job_type'] == 2:
return "#272844"
elif self.context['job_type'] == 3:
return "#2c0716"
else:
return '#fff'
As an extra bonus, I believe you could use some sort of dict()/{} object to return the hex codes from a key lookup, rather than the if elseif elseif else statements.

setting an attribute at create retrieves None value - Python

So I have an Article class that models the articles in a store. When I create a new article, I want it to have an EAN 13 code. So I initialize the article with a 12 digits code and use the check_ean13() funtion to retrieve the control digit. It works but seems like in any moment, when the object is created, rewrite the ean13 attribute and replaces it for None. Any ideas?
Main
if __name__ == "__main__":
# create article
art1 = Article("123456789087", "Article 1", 145.6, 200.0)
print art1
print art1.get_ean13()
class Article
class Article:
def __init__(self, cod, art_name, cost, listprice):
self.ean13 = self.set_ean13(cod)
self.art_name = art_name
self.cost = cost
self.listprice = listprice
self.commission = None
self.promotion=[]
def get_ean13(self):
return self.ean13
def set_ean13(self,cod):
cd = self.check_ean13(cod)
ean13 = cod + str(cd)
self.ean13=ean13
def check_ean13(self, code):
checksum = 0
for i, digit in enumerate(reversed(code)):
checksum += int(digit) * 3 if (i % 2 == 0) else int(digit)
return (10 - (checksum % 10)) % 10
output:
None - Article 1 list price: 400.0
None
self.ean13 = self.set_ean13(cod)
set_ean13 doesn't return anything, so you're effectively doing self.ean13 = None here. Just call the method without assigning the result.
self.set_ean13(cod)

Python (Django) Class that aliases/overloads list index behavior to attributes

I have a class that stores information about a week:
from django.db import models
#A django model, so can't subclass list (at least not easily)
class MyWeek(models.Model):
sunday = "foo"
monday = "foo"
tuesday = "foo"
wednesday = "foo"
thursday = "foo"
friday = "foo"
saturday = "foo"
I'd like to be able to access these attributes as if the class was a list:
aweek = Myweek()
#I want this
aweek[0] = "bar"
myvar = aweek[1]
#To be shorthand for this
aweek.monday = "bar"
myvar = aweek.tuesday
#and of course
aweek[7]
ValueError/IndexError: Week indexes monday to 0 and sunday to 6, there is no 7
Everything about python makes think this is possible and easy, if only I know the right set of things to overload.
I've thought of #property, but that doesn't help so much because I want to be able to use a variable to access it:
#I want to be able to do this
aweek[somevar] = "bar"
#and via property, i'd have to use exec
#and this is just ugly and scary from an "oh god, what could somevar be" perspective
exec("aweek.%s = 'bar'" % somevar)
#Or, as kojiro pointed out below, it could be done like this:
setattr(aweek, "somevar", "bar")
Thanks.
Edit: Working code, hattip to kojiro for helping with the right methods to overload:
# overload []
def __getitem__(self, index):
index = int(index) #will raise value error if uncoercable, this is desired behavior
if index < 0 or index > 6:
raise ValueError("Requires an integer index between 0 and 6, monday is 0 sunday is 6")
if index == 0:
return self.monday
elif index == 1:
return self.tuesday
elif index == 2:
return self.wednesday
elif index == 3:
return self.thursday
elif index == 4:
return self.friday
elif index == 5:
return self.saturday
elif index == 6:
return self.sunday
# overload set []
def __setitem__(self, index, item):
index = int(index) #will raise value error if uncoercable, this is desired behavior
if index < 0 or index > 6:
raise ValueError("Requires an integer index between 0 and 6, monday is 0 sunday is 6")
if index == 0:
self.monday = item
return
elif index == 1:
self.tuesday = item
return
elif index == 2:
self.wednesday = item
return
elif index == 3:
self.thursday = item
return
elif index == 4:
self.friday = item
return
elif index == 5:
self.saturday = item
return
elif index == 6:
self.sunday = item
return
To create a list-like object in python you need to create the following methods:
__len__, __getitem__, __setitem__, __delitem__, __iter__, and __contains__
Link to explanatory example.

Numerology with Python And Django

i have a function that give me the result that im expecting in console mode, but if i try to use the function with Django, the page never load and just have a loop calculating and never end.
Any idea ?
*sorry with my english
Console function (WORK GREAT):
def sum_digitos(n):
sum = 0;
while n != 0:
sum += n % 10
n /= 10
if sum > 9:
x = str(sum)
y =list(x)
sum = int(y[0]) + int(y[1])
return sum
print sum_digitos(2461978)
Django views:
def Calcular(request):
if request.method == 'POST':
form = NumerologiaForm(request.POST)
if form.is_valid():
sum = 0;
ano = str(request.POST['fecha_year'])
mes = str(request.POST['fecha_month'])
dia = str(request.POST['fecha_day'])
data = dia + mes + ano
fecha = int(data)
while fecha != 0:
f = fecha
sum += f % 10
f /= 10
if sum > 9:
x = str(sum)
y =list(x)
sum = int(y[0]) + int(y[1])
resultado = get_object_or_404(Numero,numero = sum)
return HttpResponseRedirect(resultado.get_absolute_url())
else:
form = NumerologiaForm()
return render_to_response('numerologiaForm.html',{'form':form})
Try:
f = fecha
while f!= 0:
sum += f % 10
f /= 10
if sum > 9:
x = str(sum)
y =list(x)
sum = int(y[0]) + int(y[1])
It seems you were changing f, but checking fecha for the looping.
Sanjay's answer is the correct one, and I recommend it. I just wanted to ask why you didn't just do:
from numerology import sum_digitos
def Calcular(request):
# In your code, you return HttpResponseRedirect using a nonexistent
# "resultado" variable if the form is not valid. This will raise an
# exception. I think you meant to indent "return Http..." one step more.
if request.method == 'POST':
form = NumerologiaForm(request.POST)
else:
form = NumerologiaForm()
# "or..." part of next line not needed if form.is_valid() returns
# False for a blank form.
if not form.is_valid() or form == NumerologiaForm():
return render_to_response('numerologiaForm.html', {'form': form})
ano = str(request.POST['fecha_year'])
mes = str(request.POST['fecha_month'])
dia = str(request.POST['fecha_day'])
resultado = get_object_or_404(Numero,
numero=sum_digitos(int(dia + mes + ano)))
return HttpResponseRedirect(resultado.get_absolute_url())
You had a working function in Python already... why not just import it and use it?
There's no need to go to all that work to sum the digits in that number, because the sum of the digits is num % 9. If num % 9 is zero, then the actual sum of digits is 9.
By changing your method to
def sum_digitos(n):
sum_ = n % 9
return sum_ if sum_ != 0 else 9
You will completely avoid whatever issue was happening inside your original method.
You don't say what the rest of your environment is like, but you should be using f //= 10 to ensure that you're performing integer division.