How to clean a specific field in Django forms.Form? - python

I have a Django form like this.
class TransactionForm(forms.Form):
start = forms.DateField()
end = forms.DateField()
I wanted to change the value before running validation:
def clean_start(self):
start = sef.cleaned_data.get('start')
return bs_to_ad(start) #This function returns date in 'YYYY-MM-DD' format
The problem is that this method runs in forms.ModelForm object but doesn't in forms.Form object.

You can modify the data before calling __init__ method using a custom __init__ method like this
class TransactionForm(forms.Form):
start = forms.DateField()
end = forms.DateField()
def __init__(self, **kwargs):
if "data" in kwargs:
start = kwargs.get("data").get("start")
# modify start
kwargs["data"]["start"] = start
super().__init__(self, **kwargs)

Simply doing this works fine.
class TransactionFrom(forms.Form):
start = forms.DateField()
end = forms.DateField()
def clean(self):
data = self.cleaned_data
if 'start' in data.keys():
start = bs_to_ad(data.get('start'))
if 'end' in data.keys():
end = bs_to_ad(data.get('end'))
self.cleaned_data.update({'start': start, 'end': end})

Related

Python project help (classes/expected type)

I am working on a project for school, simulating a payroll program, and I am getting an error. The error I am getting is
'Expected type 'Classification', got 'Employee' instead'. The relevant code is (I put *** around the code generating the error, it is the 5th function under the Employee Class).
class Employee:
def __init__(self, emp_id, first_name, last_name, address, city, state, zipcode, clas = None):
self.emp_id = emp_id
self.first_name = first_name
self.last_name = last_name
self.address = address
self.city = city
self.state = state
self.zipcode = zipcode
self.classification = clas
def make_hourly(self, hourly_rate):
self.clas = Hourly(hourly_rate)
self.classification = self.clas
def make_salaried(self, salary):
self.clas = Salaried(salary)
self.classification = self.clas
def make_commissioned(self, salary, rate):
self.clas = Commissioned(rate, salary)
self.classification = self.clas
def issue_payment(self):
***pay = Classification.compute_pay(self)***
print('Mailing', pay, 'to', self.first_name, self.last_name, 'at', self.address, self.city, self.state, self.zipcode)
class Classification(ABC):
''' Interface for employee classifications '''
#abstractmethod
def compute_pay(self):
pass
class Hourly(Classification):
''' Manages timecard info. Computes pay '''
def __init__(self, hourly_rate):
self.hourly_rate = hourly_rate
self.timecards = [] # A list of floats representing hours worked
def compute_pay(self):
for i in list_of_timecards:
if i[0] == self.emp_id:
self.timecards.extend(i[1:])
total = list(map(float, self.timecards))
total = sum(total)
self.timecards.clear()
return total * self.hourly_rate
def add_timecard(self, hours):
self.timecards.append(hours)
class Salaried(Classification):
def __init__(self, salary):
self.salary = salary
def compute_pay(self):
return self.salary / 24
class Commissioned(Salaried):
def __init__(self, salary, commission_rate):
self.commission_rate = commission_rate
self.salary = salary
self.receipts = []
def add_receipt(self, amount):
self.receipts.append(amount)
def compute_pay(self):
for i in list_of_receipts:
if i[0] == self.emp_id:
self.receipts.extend(i[1:])
total = list(map(float, self.receipts))
total = sum(total)
self.receipts.clear()
return (self.salary / 24) + ((self.commission_rate / 100) * total)
My understanding of the problem is that I need to pass my 'employee' object to the 'compute_pay' function, which then passes it to the relevant child class (hourly etc...) to run and return the result. I have tried changing
pay = Classification.compute_pay(self)
to
pay = Classification.compute_pay(self.clas)
however that returns error 'AttributeError: 'Employee' object has no attribute 'clas'
which makes no sense. Maybe it is that I am not assigning the employees to the class correctly?
The code for that is (it pulls from a CSV file, and it is pulling the data correctly and generating the class objects, I have checked)
def load_employees():
f = open("employees.csv")
f.readline() # skip header line
for line in f:
fields = line.strip().split(',')
emp = Employee(*fields[:7])
if fields[7] == '3':
clas = Hourly(fields[10]) # Need to define Hourly
emp.classification = clas
elif fields[7] == '2':
clas = Commissioned(fields[8], fields[9])
emp.classification = clas
elif fields[7] == '1':
clas = Salaried(fields[8])
emp.classification = clas
employees.append(emp)
I will figure out your line Classification.compute_pay(self):
Classification => the class Classification
compute_pay => class
method self => this = an Employee instance
pass means do nothing and is used to avoid unneccessary code.
Every class method has self as an argument to allow refering to this instance of the class.
To pass an argument (here your employee) use a parameter. Also implementing a method of the parent class overrides this method.
Every function compute_pay should have a second argument
def compute_pay(self, employee):
# do your stuff
And then you can use this line in issue_payment
pay = self.clas.compute_pay(self)
Two issues here,
Firstly, your Employee instance has two attributes: clas and classification. However, in your constructor, only classification is set.
def __init__(...
...
self.classification = clas
But self.clas is not set to anything. That's why you are getting that error 'Employee' object has no attribute 'clas'. It is only set when one of the make_hourly, make_salaried, or make_commissioned methods are invoked. So when you load the employees CSV, instead of manually creating the instance like you are doing here
clas = Hourly(fields[10])
you should be calling the method make_hourly on your emp instance, like so
emp.make_hourly(fields[10])
It's worth noting that fields[10] is terrible naming. Instead of unpacking all the fields at once, try to unpack them during the for loop:
for a, b, c, d in csv:
...
Secondly, this line of code is wrong in multiple ways
pay = Classification.compute_pay(self)
compute_pay is not a static function or a classmethod. So it shouldn't be called on the Classification class itself, but the Classification instance. This is what you stored in your self.clas attribute. So, compute_pay should be called on self.clas:
def issue_payment(self):
pay = self.clas.compute_pay()
...
In addition to that, when you call a method of a class from inside of another method in the same class, you don't ever need to pass the self argument. It is implied. So even if compute_pay was static or a class method, which it isn't, it would be called like so,
Classification.compute_pay()
Notice there is no self inside the parentheses. Similarly, when you call another method that is not static, self is never passed as an argument:
def my_method(self):
self.another_method()

how can I expire tokens after 1 minute?

I am trying to expire tokens after its creation with a max duration of 1 minute to meet security requirements. my function looks like this, but I don't think is doing it the right way, and I Would like to know what is the best way to expire the token after 1 minute? I am using the technique of diffing two times. the following function works under models.py
def is_token_expired(self):
if self.token == None:
return False
now = datetime.datetime.utcnow().replace(tzinfo=utc)
timediff = now - self.created_at
if timediff.seconds / 60 - 1 > 0:
return True
return False
I think the elegant way to archive your goal is leveraging django cache.
Sample code:
class Foo(models.Model):
...
def save(self, *args, **kwargs):
if not self.pk:
# save the token when record created
cache.set('token_key', '<Your token>', timeout=60)
super(Foo, self).save(*args, **kwargs)
#property
def is_token_expired(self):
# check if the token expired
return cache.get('token_key') is None
#property
def token(self):
# get token
return cache.get('token_key')
It is better to use #property in your model:
from datetime import timedelta
class Foo(models.Model):
some_field = models.CharField()
creation_date = models.DateTimeField(auto_now_add=True)
#property
def is_expired(self):
if datetime.now > (self.creation_date + timedelta(minutes=1)):
return True
return False
you can change timedelta(minutes=1) to amount that your token is valid.
and use it in your code like this:
if your_instance.is_expired == True:
# do something
You can also use Django builtin cache system (that Enix mentioned) as a better approach.

ModelChoicesField returns Non-Valid-Choice error, although form is valid

If have a date picker form that filters a set of models (Sonde) and populates a ModelChoicesField. This works correctly in terms of date choice in my app, but on my canvas I constantly get the error:
Select a valid choice. That choice is not one of the available choices.
I do the init, to filter the available instances of Sonde and populate the choices of the ModelChoiceField.
From my forms.py
class date_choice(forms.Form):
avSonden = forms.ModelChoiceField(queryset = Sonde.objects.none())
def __init__(self, *args, **kwargs):
currentUserID = kwargs.pop('currentUserID', None)
super(date_choice, self).__init__(*args, **kwargs)
if currentUserID:
self.fields['avSonden'].queryset = Sonde.objects.filter(owned_by__Kundennummer = currentUserID).values_list("Serial",flat=True).distinct()
start = forms.DateField(input_formats=['%Y-%m-%d'])
end = forms.DateField(input_formats=['%Y-%m-%d'])
I had to force the clean() to ignore my change from PK to other identifier:
def clean_status(self):
#valid if a value has been selected
if self["avSonden"].value()!="":
del self._errors["avSonden"]
return self["avSonden"].value()

Django 1.11.7: How do I call a Class method in Views?

In my models.py I have a Class (Paths) with a method, validate_time that tries to access two fields of the Paths model (time_start, time_end):
class Paths(m.Model):
time_start: m.TimeField()
time_end: m.TimeField()
def validate_time(self):
start = self.time_start
end = self.time_end
print start #print start to test it out
#...some function that returns True or False
I call validate_time in my views.py:
from .models import Paths
def paths_data(request):
ps = Paths()
valid_times = ps.validate_time()
if valid_times == False:
....
I see the method, validate_time, is hit because I see the print statement
But it appears the print out says: None
But time_start and time_end have already been saved to the model as strings. How can I get them as their string value in validate_time?
I think self.time_start might not have been set as ps is an empty Path object initialized by 'ps = Paths()' and time_start does not have a default value.
If you are looking for a saved instance, you need to query database for it first with something like Paths.objects.get(your_key=your_value). More details on queries: https://docs.djangoproject.com/en/1.11/topics/db/queries/
You can use either #classmethod or #staticmethod decorator for validate_time

Create a Python User() class that both creates new users and modifies existing users

I'm trying to figure out the best way to create a class that can modify and create new users all in one. This is what I'm thinking:
class User(object):
def __init__(self,user_id):
if user_id == -1
self.new_user = True
else:
self.new_user = False
#fetch all records from db about user_id
self._populateUser()
def commit(self):
if self.new_user:
#Do INSERTs
else:
#Do UPDATEs
def delete(self):
if self.new_user == False:
return False
#Delete user code here
def _populate(self):
#Query self.user_id from database and
#set all instance variables, e.g.
#self.name = row['name']
def getFullName(self):
return self.name
#Create a new user
>>u = User()
>>u.name = 'Jason Martinez'
>>u.password = 'linebreak'
>>u.commit()
>>print u.getFullName()
>>Jason Martinez
#Update existing user
>>u = User(43)
>>u.name = 'New Name Here'
>>u.commit()
>>print u.getFullName()
>>New Name Here
Is this a logical and clean way to do this? Is there a better way?
Thanks.
You can do this with metaclasses. Consider this :
class MetaCity:
def __call__(cls,name):
“”“
If it’s in the database, retrieve it and return it
If it’s not there, create it and return it
““”
theCity = database.get(name) # your custom code to get the object from the db goes here
if not theCity:
# create a new one
theCity = type.__call__(cls,name)
return theCity
class City():
__metaclass__ = MetaCity
name = Field(Unicode(64))
Now you can do things like :
paris = City(name=u"Paris") # this will create the Paris City in the database and return it.
paris_again = City(name=u"Paris") # this will retrieve Paris from the database and return it.
from : http://yassinechaouche.thecoderblogs.com/2009/11/21/using-beaker-as-a-second-level-query-cache-for-sqlalchemy-in-pylons/
Off the top of my head, I would suggest the following:
1: Use a default argument None instead of -1 for user_id in the constructor:
def __init__(self, user_id=None):
if user_id is None:
...
2: Skip the getFullName method - that's just your Java talking. Instead use a normal attribute access - you can convert it into a property later if you need to.
What you are trying to achieve is called Active Record pattern. I suggest learning existing systems providing this sort of things such as Elixir.
Small change to your initializer:
def __init__(self, user_id=None):
if user_id is None:

Categories

Resources