Django Python Where to add Auxiliary Functions to not repeat code? - python

I come from native POO programming languages and I'm new in Python, also Django.
I see that in Django they put all code from an app in same views.py or models.py.
Now I'm in a view called:
def create_ticket(self):
....
And inside I have this code
is_staff=User.objects.get(pk=request.user.id).is_staff
if is_staff==1:
R_Client_Accountant = LinkUserContable.objects.filter(contable=mongoId)
print(R_Client_Accountant)
accountantList = []
for relation in R_Client_Accountant:
try:
rmongosql = RMongoSql.objects.get(mongoId=relation.user.id)
user = User.objects.get(pk=rmongosql.helpdeskId)
accountantList.append((user.id,user.username))
except:
pass
else:
R_Client_Accountant = LinkUserContable.objects.filter(user=mongoId)
accountantList = []
for relation in R_Client_Accountant:
try:
rmongosql = RMongoSql.objects.get(mongoId=relation.contable.id)
user = User.objects.get(pk=rmongosql.helpdeskId)
accountantList.append((user.id,user.username))
except:
pass
As you can see I repeat code inside the 'try' just exchanging {user XOR contable}
If I want to write a function passing by parameter this {user XOR contable} where should I place it ?
To me, in corresponding model from models.py is not correct because there are so much code lines referring to different models and views.py is just for view functions right ?
Regards,
VĂ­ctor.

you can use the getattr function to use a string to get the required attribute getattr(relation, relation_attr)
your function would look like this
def create_ticket(self):
is_staff=User.objects.get(pk=request.user.id).is_staff
if is_staff==1:
relation_attr = 'user'
else:
relation_attr = 'contable'
R_Client_Accountant = LinkUserContable.objects.filter(contable=mongoId)
print(R_Client_Accountant)
accountantList = []
for relation in R_Client_Accountant:
try:
rmongosql = RMongoSql.objects.get(mongoId=getattr(relation, relation_attr).id)
user = User.objects.get(pk=rmongosql.helpdeskId)
accountantList.append((user.id, user.username))
except:
pass

Related

Django if elif else statement

I'm trying to print the result according to the user's age selection in the form, but my if,elif and else statements are not working.
class Quiz(models.Model):
age_choices = (('10-12', '10-12'),
('13-16', '13-16'),
('17-20', '17-20'),
('21-23','21-23'),
)
age = models.CharField(max_length = 100, choices = age_choices)
views.py
def create_order(request):
form = QuizForm(request.POST or None)
if request.method == 'POST':
quiz = Quiz.objects
if quiz.age=='10-12':
print("10-12")
elif quiz.age=='13-16':
print("13-16")
elif quiz.age=='17-20':
print("17-20")
elif quiz.age=='21-23':
print("21-23")
else:
return None
context = {'form':form}
return render(request, "manualupload.html", context)
quiz = Quiz.objects will return a django.db.models.manager.Manager object and this can be further used to fetch the objects from database belonging to that particular model. The appropriate query set will be quiz = Quiz.objects.all() Then you will get the list of all objects in that belong to Quiz model. Once you get list of all objects, you can get the specific object either by indexing or by filtering using a specific query that you need to look into and then for that particular object you can get the age property.
Refer to official django documentation about creating queries for more information.
As #Abhijeetk431 mentioned, your issue lies in quiz = Quiz.objects.
If you use type(quiz), you will find that it outputs django.db.models.manager.Manager. This is not what you want, as age is a property of the Quiz class, not the Manager class.
For starters, refer to this.
This will return you a Queryset list, something akin to an Excel table. age is akin to the column in the table. To get age, what you want is the row (the actual Quiz object) in said table, which you can achieve using get or using the square brackets [].
Thus, your code should look something like this:
Model.objects.all()[0]
That would return the correct object(only the first row) and allow you to get the column value.
However, further clarification will be needed though, to know exactly what your problem is aside from 'it doesn't work'. How did you know your code is not working; what did the debugger tell you?

Improving code for similar code found

I passed codeclimate to my code, and I obtained the following:
Similar code found in 1 other location
This is my code:
stradd = 'iterable_item_added'
if stradd in ddiff:
added = ddiff[stradd]
npos_added = parseRoots(added)
dics_added = makeAddDicts(localTable, pk, npos_added)
else:
dics_added = []
strchanged = 'values_changed'
if strchanged in ddiff:
updated = ddiff[strchanged]
npos_updated = parseRoots(updated)
dics_updated = makeUpdatedDicts(localTable, pk, npos_updated)
else:
dics_updated = []
Where iterable_item_added and values_changed are repeated. How to change it?
just abstract the parameters and create an helper method:
def testmethod(name,localTable,m,ddiff,pk):
if name in ddiff:
npos = parseRoots(ddiff[name])
rval = m(localTable, pk, npos)
else:
rval = []
return rval
the call it:
dics_added = testmethod('iterable_item_added',localTable,makeAddDicts,ddiff,pk)
dics_updated = testmethod('values_changed',localTable,makeUpdatedDicts,ddiff,pk)
note: be careful when factorizing code, you can introduce bugs (and make code better readable :)).
Also: that helper method forces to pass a lot of local variables. Maybe creating an object and member variables would simplify even more.
In that case, it appears to be a bit "overkill" to do that in order to make your review tool shut up.

Why is this class and corresponding attribute not being destroyed between requests?

I can not understand this behavior at all. I asked a question yesterday or the day before thinking it was something with bottle.py, but after trying all kinds of possible solutions, even converting my app over to flask, I have pinpointed the behavior to a single, very simple, class, but I have NO idea why this is happening. It's confusing the hell out of me, but I would really like to understand this if anyone can please shed some light on it.
Ok, so first I have a class called Page which simplifies setting up templates a bit, this is the offending class:
class Page:
"""The page object constructs the webpage and holds associated variables and templates"""
def __init__(self, template=None, name = '', title='',template_vars={}, stylesheets=[], javascript=[]):
# Accepts template with or without .html extension, but must be added for lookup
self.stylesheet_dir = '/css'
self.javascript_dir = '/js'
self.template = template
self.template_vars = {}
self.name = name
self.title = title
self.stylesheets = stylesheets
self.javascript = javascript
self.template_vars['debug'] = _Config.debug
self.template_vars['title'] = self.title
self.template_vars['stylesheets'] = self.stylesheets
self.template_vars['javascript'] = self.javascript
def render(self):
"""Should be called after the page has been constructed to render the template"""
if not self.template.endswith(_Config.template_extension):
self.template += '.' + _Config.template_extension
if not self.title:
if self.name:
self.title = _Config.website + _Config.title_delimiter + self.name
else:
# If title not given use template name
self.title = _Config.website + _Config.title_delimiter + self.template.rstrip('.html')
try:
template = env.get_template(self.template)
except AttributeError:
raise (AttributeError, 'template not set')
rendered_page = template.render(self.template_vars)
return rendered_page
def add_stylesheet(self, name, directory=None):
# Sanitize name
if not name.endswith('.css'):
name += '.css'
if name.startswith('/'):
name = name.lstrip('/')
if not directory:
directory = self.stylesheet_dir
self.template_vars['stylesheets'].append(directory + '/' + name)
def add_javascript(self, name, directory=None):
# Sanitize name
if not name.endswith('.js'):
name += '.js'
if name.startswith('/'):
name = name.lstrip('/')
if not directory:
directory = self.javascript_dir
self.template_vars['javascript'].append(directory + '/' + name)
And here is an example of a route that the problem is exhibited:
#route('/create_account', method=['GET','POST'])
def create_account():
dbsession = db.Session()
page = Page('create account')
page.add_javascript('create_account.js')
if request.method == 'GET':
page.template = 'create_account'
page.template_vars['status'] = None
document = page.render()
dbsession.close()
return document
elif request.method == 'POST':
# Omitted
The problem lies with the method Page.add_javascript(). The next time I go to the /create_account page it is not creating a new Page object and instead reusing the old one. I know this because if I go to the page twice I will have two entires for the create_account.js in my returned html document(the template simply runs a for loop and creates a tag for any js files passed in that list). If I go 3 times it'll be listed 3 times, 40, 40 and so on. Now however if I simply change it to use the initializer and not the add_javascript method the problem goes away.
#route('/create_account', method=['GET','POST'])
def create_account():
dbsession = db.Session()
page = Page('create account', javascript=['create_account.js'])
if request.method == 'GET':
page.template = 'create_account'
page.template_vars['status'] = None
document = page.render()
dbsession.close()
return document
elif request.method == 'POST':
However I suspect something is still wrong and just for my own sanity I need to understand what the hell is going on here. What is possibly happeneing behind the scenes where the add_javascript method would be called twice on the same page object? The method is called immediately after creating a new instance of the page object, where is it possibly getting the old contents of template_vars from?
The problem is that you use mutable defaults for your Page.__init__ function. See http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments.
So you do get a new Page instance on each request, but the lists/dictionaries that hold your javascript etc are re-used.
Replace list/dict default argument values with None, check for None in __init__.

Django getting objects from a mixin

I have a small model method I'm using to get the previous and next object relative to the current object. It looks something like this:
class Article
...
def get_prev_next(self):
articles = list(Article.objects.all())
i = articles.index(self)
try:
p = articles[i - 1]
except IndexError:
p = None
try:
n = articles[i + 1]
except IndexError:
n = None
return {'prev': p, 'next': n}
It works, and may well be inefficient, but now I want to use it in a different model.
I'd like to make this into a mixin, but I can't figure out how to get the original model class name so I can run Model.objects.all() and get my list.
I have so far:
class PrevNextMixin(object):
objects = list(???.objects.all())
i = objects.index(self)
...
A mixin is still a class. The code still needs to go into a method. That method will get a self argument just as it does now.
class PrevNextMixin(object):
def get_prev_next(self):
objects = list(self.__class__.objects.all())

how to get entities which don't have certain attribute in datastore

I'm trying to make an appraisal system
This is my class
class Goal(db.Expando):
GID = db.IntegerProperty(required=True)
description = db.TextProperty(required=True)
time = db.FloatProperty(required=True)
weight = db.IntegerProperty(required=True)
Emp = db.UserProperty(auto_current_user=True)
Status = db.BooleanProperty(default=False)
Following things are given by employee,
class SubmitGoal(webapp.RequestHandler):
def post(self):
dtw = simplejson.loads(self.request.body)
try:
maxid = Goal.all().order("-GID").get().GID + 1
except:
maxid = 1
try:
g = Goal(GID=maxid, description=dtw[0], time=float(dtw[1]), weight=int(dtw[2]))
g.put()
self.response.out.write(simplejson.dumps("Submitted"))
except:
self.response.out.write(simplejson.dumps("Error"))
Now, here Manager checks the goals and approve it or not.. if approved then status will be stored as true in datastore else false
idsta = simplejson.loads(self.request.body)
try:
g = db.Query(Goal).filter("GID =", int(idsta[0])).get()
if g:
if idsta[1]:
g.Status=True
try:
del g.Comments
except:
None
else:
g.Status=False
g.Comments=idsta[2]
db.put(g)
self.response.out.write(simplejson.dumps("Submitted"))
except:
self.response.out.write(simplejson.dumps("Error"))
Now, this is where im stuck..."filter('status=',True)".. this is returning all the entities which has status true.. means which are approved.. i want those entities which are approved AND which have not been assessed by employee yet..
def get(self):
t = []
for g in Goal.all().filter("Status = ",True):
t.append([g.GID, g.description, g.time, g.weight, g.Emp])
self.response.out.write(simplejson.dumps(t))
def post(self):
idasm = simplejson.loads(self.request.body)
try:
g = db.Query(Goal).filter("GID =", int(idasm[0])).get()
if g:
g.AsmEmp=idasm[1]
db.put(g)
self.response.out.write(simplejson.dumps("Submitted"))
except:
self.response.out.write(simplejson.dumps("Error"))
How am I supposed to do this? as I know that if I add another filter like "filter('AsmEmp =', not None)" this will only return those entities which have the AsmEmp attribute what I need is vice versa.
You explicitly can't do this. As the documentation states:
It is not possible to query for entities that are missing a given property.
Instead, create a property for is_assessed which defaults to False, and query on that.
could you not simply add another field for when employee_assessed = db.user...
and only populate this at the time when it is assessed?
The records do not lack the attribute in the datastore, it's simply set to None. You can query for those records with Goal.all().filter('status =', True).filter('AsmEmp =', None).
A few incidental suggestions about your code:
'Status' is a rather unintuitive name for a boolean.
It's generally good Python style to begin properties and attributes with a lower-case letter.
You shouldn't iterate over a query directly. This fetches results in batches, and is much less efficient than doing an explicit fetch. Instead, fetch the number of results you need with .fetch(n).
A try/except with no exception class specified and no action taken when an exception occurs is a very bad idea, and can mask a wide variety of issues.
Edit: I didn't notice that you were using an Expando - in which case #Daniel's answer is correct. There doesn't seem to be any good reason to use Expando here, though. Adding the property to the model (and updating existing entities) would be the easiest solution here.

Categories