Skip to content

Instantly share code, notes, and snippets.

@only-entertainment
Created March 24, 2012 00:42
Show Gist options
  • Save only-entertainment/2176789 to your computer and use it in GitHub Desktop.
Save only-entertainment/2176789 to your computer and use it in GitHub Desktop.
Validate a VIN using Python
class VINLookupForm(Form):
"""
Lookup a VIN form
"""
vin = TextField(u'Enter VIN',
validators=[validators.Required(u'VIN is required for lookup.')])
def validate_vin(self, field):
"""
Validate a VIN against the 9th position checksum
See: http://en.wikipedia.org/wiki/Vehicle_Identification_Number#Check_digit_calculation
Test VINs:
1M8GDM9AXKP042788
11111111111111111
"""
POSITIONAL_WEIGHTS = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2]
ILLEGAL_ALL = ['I', 'O', 'Q']
ILLEGAL_TENTH = ['U','Z','0']
LETTER_KEY = dict(
A=1,B=2,C=3,D=4,E=5,F=6,G=7,H=8,
J=1,K=2,L=3,M=4,N=5, P=7, R=9,
S=2,T=3,U=4,V=5,W=6,X=7,Y=8,Z=9,
)
if len(field.data) == 17:
vin = field.data.upper()
for char in ILLEGAL_ALL:
if char in vin:
raise ValidationError('Field cannot contain "I", "O", or "Q".')
if vin[10] in ILLEGAL_TENTH:
raise ValidationError('Field cannot contain "U", "Z", or "0" in position 10.')
check_digit = vin[8]
pos=sum=0
for char in vin:
value = int(LETTER_KEY[char]) if char in LETTER_KEY else int(char)
weight = POSITIONAL_WEIGHTS[pos]
sum += (value * weight)
pos += 1
calc_check_digit = int(sum) % 11
if calc_check_digit == 10:
calc_check_digit = 'X'
if str(check_digit) != str(calc_check_digit):
raise ValidationError('Invalid VIN.')
else:
raise ValidationError('Field must be 17 characters.')
@en0
Copy link

en0 commented May 8, 2014

Line 34 should read:
if vin[9] in ILLEGAL_TENTH:

The year code cannot be U Z or Zero at offset 10. Remember, python uses a zero based index.

Thank you for the code. It works great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment