patternpythonMinor
Conditionally set attributes in MongoDB based on form fields
Viewed 0 times
conditionallyfieldsmongodbattributesbasedformset
Problem
I have code which gets data from a
Below is a stripped down version of
``
# nothing to do with setting and val
POST request (request.form dict), compares with corresponding attribute in object accident and does some action. The code looks needlessly verbose. How can I optimize it?if accident.status == 1:
if request.form.get('reason') \
and request.form['reason'] != accident.reason:
accident.set_reason(request.form['reason'], current_user)
if request.form.get('note') \
and request.form['note'] != accident.note:
accident.note = request.form['note']
else:
if request.form.get('priority') \
and int(request.form['priority']) != accident.priority:
accident.set_priority(current_user, int(request.form['priority']))
if request.form.get('status') \
and int(request.form['status']) != accident.status:
accident.set_status(current_user, int(request.form['status']))
if request.form.get('duration') \
and int(request.form['duration']) != accident.duration:
accident.duration = int(request.form['duration'])
if request.form.get('service_status') \
and int(request.form['service_status']) != accident.service_status:
accident.set_service_status(int(request.form['service_status']))Below is a stripped down version of
Accident class, which is inconsistent because there are many fields, and sometimes setting a field requires many additional actions like logging or checking for user rights. The class derives from MongoEngine schema class.``
class Accident(Document):
priority = IntField(choices=PRIORITIES)
status = IntField(choices=STATUSES, default=0)
duration = IntField()
region = StringField()
service_status = IntField(choices=(0, 1, 2))
reason = StringField(default=u"")
note = StringField(default=u"")
def set_priority(self, user=None, priority=None):
self.priority = priority
# Functions starting with set_` do some activity that has# nothing to do with setting and val
Solution
I'm not 100% sure there is a particularly elegant way to write this. If the code did not have a different body for each
However, that is not the case, so don't get your hopes up. Regardless, there are still improvements to be made:
Overall not bad code. I don't agree with your comments on how
if statement, one could rewrite it like thisFORM_VALUES = {
"priority": accident.priority,
"status": accident.status,
"duration": accident.duration,
"service_status": accident.service_status
}
for key in FORM_VALUES:
if request.form.get(key) and int(request.form[key]) != FORM_VALUES[key]:
# As you use different functions for setting the values, this isn't possible
request.set_value(key, request.form[key])However, that is not the case, so don't get your hopes up. Regardless, there are still improvements to be made:
- You're not checking that the header values are valid integers. I'd recommend either checking they are by using
string.isdigit()or otherwise wrapping your calls toint()in a try except block.
- You can use
'reason' in request.forminstead ofrequest.form.get('reason'); they have the same meaning in the places you've used them, but the first is easier to read.
- It might be good if you used an enumeration for the values to
Accident.status. As it is, checking thataccident.status == 1doesn't tell me anything; using a meaningful identifier might solve this. You can do this quite simply, by just assigning values to each identifier:PENDING, IN_PROGRESS, FINISHED = STATUSES. I've used some random names, and assumed that there are 3 possible statuses, change this to be accurate. Then in your function, instead ofif accident.status == 1, we can haveif accident.status == PENDING, which is a lot easier to understand without needing to know the meaning of each value of status.
- In general, you should try and be consistent with the ordering of your arguments: your
set_reasontakes first areason, then auserargument, while all of your other methods take theuserargument first. Theset_service_statusdoesn't take auserargument at all, which is fairly impressive, considering it uses a user variable in the function.
Overall not bad code. I don't agree with your comments on how
@property would be inappropriate there, but it's far from the end of the world. In general, I'd try and be more careful to validate user input, but it may be that you do not need to worry about that.Code Snippets
FORM_VALUES = {
"priority": accident.priority,
"status": accident.status,
"duration": accident.duration,
"service_status": accident.service_status
}
for key in FORM_VALUES:
if request.form.get(key) and int(request.form[key]) != FORM_VALUES[key]:
# As you use different functions for setting the values, this isn't possible
request.set_value(key, request.form[key])Context
StackExchange Code Review Q#42259, answer score: 8
Revisions (0)
No revisions yet.