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)
Related
In my django forms.py file, I am trying to replace two occurrences of repeated validation code. Each attempt I make to have only one occurrence of each, does not seem to work.
I cannot figure out how to write the code so that I have only one occurrence of each of the repeated code in the validation. It should be possible, but I cannot understand how to achieve this.
I am hoping that someone can help me out as this has me confused.
Here is my validation code:
def clean(self):
cd_cdf = super(CertificationDetailsForm, self).clean()
# Must check the most specific cases first, then the general cases.
if 'certification_type' in cd_cdf and cd_cdf['certification_type'] == '':
self._errors['certification_type'] = self.error_class([_("This field is required.")])
elif 'certification_type' in cd_cdf and cd_cdf['certification_type'] == display_types.ENTER_MY_OWN_TYPE_DESCRIPTION:
if 'certification_type_description' in cd_cdf and len(cd_cdf['certification_type_description'].strip()) == 0:
self._errors['certification_type_description'] = self.error_class([_("This field is required.")])
# repeated code occurrence #1.1.
if 'certification_title' in cd_cdf and len(cd_cdf['certification_title'].strip()) == 0:
self._errors['certification_title'] = self.error_class([_("This field is required.")])
# repeated code occurrence #2.1.
if 'certification_date' in cd_cdf and cd_cdf['certification_date'] is not None:
if cd_cdf['certification_date'] > date.today():
self._errors['certification_date'] = self.error_class([_("Date must not be greater than today.")])
elif 'certification_type' in cd_cdf and cd_cdf['certification_type'] != display_types.ENTER_MY_OWN_DETAILS:
# repeated code occurrence #1.2.
if 'certification_title' in cd_cdf and len(cd_cdf['certification_title'].strip()) == 0:
self._errors['certification_title'] = self.error_class([_("This field is required.")])
# repeated code occurrence #2.2.
if 'certification_date' in cd_cdf and cd_cdf['certification_date'] is not None:
if cd_cdf['certification_date'] > date.today():
self._errors['certification_date'] = self.error_class([_("Date must not be greater than today.")])
elif 'certification_type' in cd_cdf and cd_cdf['certification_type'] == display_types.ENTER_MY_OWN_DETAILS:
if 'certification_description' in cd_cdf and len(cd_cdf['certification_description'].strip()) == 0:
self._errors['certification_description'] = self.error_class([_("This field is required.")])
# remove the entered value and/or assign a default value, when the certification type only requires minimum data.
if 'certification_type_description' in cd_cdf and len(cd_cdf['certification_type_description'].strip()) > 0:
cd_cdf['certification_type_description'] = None
if 'certification_title' in cd_cdf and len(cd_cdf['certification_title'].strip()) > 0:
cd_cdf['certification_title'] = None
if 'certification_institution' in cd_cdf and len(cd_cdf['certification_institution'].strip()) > 0:
cd_cdf['certification_institution'] = None
if 'certification_date' in cd_cdf and cd_cdf['certification_date'] is not None:
cd_cdf['certification_date'] = None
return cd_cdf
Here is the types code, just in case:
CERTIFICATE = 1
CERTIFICATE_LEVEL_I = 2
CERTIFICATE_LEVEL_II = 3
CERTIFICATE_LEVEL_III = 4
CERTIFICATE_LEVEL_IV = 5
STANDARD_CERTIFICATE = 6
INTERMEDIATE_CERTIFICATE = 7
ADVANCED_CERTIFICATE = 8
ACADEMIC_CERTIFICATE = 9
PROFESSIONAL_CERTIFICATE = 10
OTHER_CERTIFICATE = 11
ENTER_MY_OWN_TYPE_DESCRIPTION = 7777 # 7777 triggers a hidden text field to be displayed.
ENTER_MY_OWN_DETAILS = 9999
CERTIFICATION_TYPES = (
(CERTIFICATE, _('Certificate')),
(CERTIFICATE_LEVEL_I, _('Certificate Level I')),
(CERTIFICATE_LEVEL_II, _('Certificate Level II')),
(CERTIFICATE_LEVEL_III, _('Certificate Level III')),
(CERTIFICATE_LEVEL_IV, _('Certificate Level IV')),
(STANDARD_CERTIFICATE, _('Standard Certificate')),
(INTERMEDIATE_CERTIFICATE, _('Intermediate Certificate')),
(ADVANCED_CERTIFICATE, _('Advanced Certificate')),
(ACADEMIC_CERTIFICATE, _('Academic Certificate')),
(PROFESSIONAL_CERTIFICATE, _('Professional Certificate')),
(OTHER_CERTIFICATE, _('Other Certificate')),
(ENTER_MY_OWN_TYPE_DESCRIPTION, _('Enter my own Type Description')),
(ENTER_MY_OWN_DETAILS, _('Enter my own details'))
)
Like this:
def clean(self):
cd_cdf = super(CertificationDetailsForm, self).clean()
ctype = 'certification_type'
ctypedesc = 'certification_type_description'
ctitle = 'certification_title'
cdate = 'certification_date'
cdesc = 'certification_description'
cinst = 'certification_institution'
# Must check the most specific cases first, then the general cases.
if ctype in cd_cdf:
if cd_cdf[ctype] == '':
self._errors[ctype] = self.error_class([_("This field is required.")])
elif (cd_cdf[ctype] == display_types.ENTER_MY_OWN_TYPE_DESCRIPTION) or (cd_cdf[ctype] != display_types.ENTER_MY_OWN_DETAILS):
if cd_cdf[ctype] == display_types.ENTER_MY_OWN_TYPE_DESCRIPTION:
if ctypedesc in cd_cdf and len(cd_cdf[ctypedesc].strip()) == 0:
self._errors[ctypedesc] = self.error_class([_("This field is required.")])
else:
if ctitle in cd_cdf and len(cd_cdf[ctitle].strip()) == 0:
self._errors[ctitle] = self.error_class([_("This field is required.")])
if cdate in cd_cdf and cd_cdf[cdate] is not None:
if cd_cdf[cdate] > date.today():
self._errors[cdate] = self.error_class([_("Date must not be greater than today.")])
elif cd_cdf[ctype] == display_types.ENTER_MY_OWN_DETAILS:
if cdesc in cd_cdf and len(cd_cdf[cdesc].strip()) == 0:
self._errors[cdesc] = self.error_class([_("This field is required.")])
# remove the entered value and/or assign a default value, when the certification type only requires minimum data.
forcheck = [ctypedesc, ctitle, cinst]
for i in forcheck:
if i in cd_cdf and len(cd_cdf[i].strip()) > 0:
cd_cdf[i] = None
if cdate in cd_cdf and cd_cdf[cdate] is not None:
cd_cdf[cdate] = None
return cd_cdf
I replaced your frequently mentioned strings with self-obvious variables and joined the second and third conditions. I haven't tested this.
I agree with the first answer, it's ineligant and unpythonic, but I have no idea what all these conditions are about so I can't shorten the code any further.
I can't seem to find how to, in Python 2.7, fill in a variable name instead of an index. I only find answers for other programming languages.
The file that is imported contains multiple columns, but I only want to add columns defined and asked for in the Query function to Data_BM. So how can IlocX be seen as an index.
Even if there is an easier way, I would just like to know how to put a variable on an index position. Thank you in advance.
# function for the datafile name
def datafilename():
print "Type the data filename, for example: myfile.csv : \n"
dataname = raw_input()
print dataname, 'Correct? [Y/N]'
yn = raw_input()
if yn == 'Y' or yn == 'y':
return dataname
else:
datafilename()
# function for the column numbers
def query(var):
print 'Type column number for',var,':'
loc = raw_input()
try:
loc = int(loc)
except:
loc = loc
print loc, 'Correct? [Y/N]'
yn = raw_input()
if yn == 'Y' or yn == 'y':
if type(loc) == int:
return loc
elif loc == 'NA' or loc == 'na':
return loc
else:
print 'Please type column as integer value'
query(var)
else:
query(var)
#Ask for column locations
loc1 = query("X")
loc2 = query("Y")
loc3 = query("Z")
loc4 = query("A")
loc5 = query("B")
Iloc1 = int(loc1-1)
Iloc2 = int(loc2-1)
Iloc3 = int(loc3-1)
Iloc4 = int(loc4-1)
Iloc5 = int(loc5-1)
# Asking for data file name
dataname = datafilename()
#Get data
Data_BM = pd.read_csv(dataname)
Data_BM = Data_BM[Iloc1,Iloc2,Iloc3,Iloc4,Iloc5]
I updated my file, I forgot to put in the query function. The user is asked to fill in the column number for for example X. The user types 1, which is loc1. Iloc 1 = 0. So 0 is the indexnumber. How can I have Iloc1 be the indexnumber in Data_BM = Data_BM[Iloc1,Iloc2,Iloc3,Iloc4,Iloc5] and the same accounts for the others. The reason I want this is because the columns might change but I want to make it easy for the user.
Short answer is no,
Long answer is why?
If you have a list of variables like a1, a2, a3, a4, ..., an, make a list of them, or a dictionary if you want to access it by strings.
The closest thing you can do is:
vars = {}
for i in range(10):
vars["Ilock"+str(i)] = something()
vars["Ilock4"] = 42
But it's ugly and not convenient.
I'd like to have a Django form which accepts a bitcoin address from a user. What would be the best way to validate whether or not this address is legitimate?
I could try writing my own implementation, but in regards to these things I'm assuming it's always better to go with something tried and tested than create something with potential holes. Is there good python code I can use to make a custom field for my django forms, or any resources that have already done this?
Alternatively, might it be better to perhaps skip the whole custom form field process, for example, and validate the address in the view using a pycoin library instead? If I were to do it this way, however, how would I return the error in the form?
BCAddressField acomplishes exactly what I was looking for. Note however that you must replace from django.forms.util import ValidationError with from django.core.exceptions import ValidationError, as the former is deprecated.
Bech32:
def btc_validation(address):
a = str(address)
length = 0
valid = False
not_btc = False
for i in a:
length += 1
if length == 42:
if a[2] == '1' and a[0] == 'b' and a[1] == 'c':
for i in a:
if i == 'O' or i == 'I':
not_btc = True
break
if not_btc == True:
return valid
else:
valid = True
return valid
else:
return 'didn\'t start with bc1'
else:
return 'it\'s short'
P2PKH:
import base58
def bitcoin_address_validation(bitcoinAddress):
"""
Base58 (P2PKH)
"""
try:
base58Decoder = base58.b58decode(bitcoinAddress).hex()
prefixAndHash = base58Decoder[:len(base58Decoder) - 8]
checksum = base58Decoder[len(base58Decoder) - 8:]
hash = prefixAndHash
for x in range(1, 3):
hash = hashlib.sha256(binascii.unhexlify(hash)).hexdigest()
if (checksum == hash[:8]):
valid = True
else:
valid = False
except:
valid = False
pass
return valid
Reference
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.
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...