Write a function to reduce duplicate code - python

I have two very similar for loops, I want to have an inner function to reduce the duplicate codes, they look like this:
team_members = TeamMember.objects.all()
managers = Manager.objects.all()
for m in managers:
name = f"{m.name.first_name} {m.name.last_name}"
//reset of the code are the same
for t in team_members:
name = f"{t.member.first_name} {t.member.last_name}"
//reset of the code are the same
So the problem is managers and team_members querysets have different field names for people's names.
If I want to write an inner function, how to solve the different field names?

you could pass in m.name and t.member to that function which would allow it to access that item.
for m in managers:
func(m.name)
for t in team_members:
func(t.member)
def func(member):
name = f'{member.first_name} {member.last_name}
#Rest of code

Here is the inner function which will take objs as input and fetch the values based on objects attribute.
def inner_fun(objs):
for obj in objs:
if hasattr(obj, 'name'):
name_obj = getattr(obj, 'name')
else:
name = getattr(obj, 'member')
name = f"{name_obj.first_name} {name_obj.last_name}"
return name
team_members = TeamMember.objects.all()
managers = Manager.objects.all()
team_name = inner_fun(team_members)
manager_name = inner_fun(managers)

Tom Karzes solution in code:
team_members = TeamMember.objects.all()
managers = Manager.objects.all()
for group, attr_name in zip([team_members, managers], ['name', 'member']):
for person in group:
name = f"{getattr(person, attr_name).first_name} {getattr(person, attr_name).last_name}"

Related

Python - Running through the same code block in a loop for different variable

I have this below set of code where I perform some manipulation based after pulling some data from a source Dataframe called df.
Customer_data = []
for i in range(0, len(df)):
try:
Customer = (re.search(r'(Customer"=>).*?(,)', df[i]).group(0).split('=>')[1].replace('"','').replace(',',''))
except:
Customer = ''
Customer_data.append(Customer)
Customer = pd.DataFrame(Customer_data.append, columns = ['Customer'])
I am trying to have the above code repeated for set of variables wherein I would replace the variable Customer with another variable. How could I generalise the above code such that it could be reused for other variables as well in a loop.
Example variables : Product, ModelName
You can put it inside the function, where you pass the name string of your variable (as seen in DataFrame).
Just change search part to include correct name r'({}"=>).*?(,)'.format(name).
def my_func(df, name):
Customer_data = []
for i in range(0, len(df)):
try:
Customer = (re.search(r'({}"=>).*?(,)'.format(name), df[i]).group(0).split('=>')[1].replace('"','').replace(',',''))
except:
Customer = ''
Customer_data.append(Customer)
Customer = pd.DataFrame(Customer_data.append, columns = ['Customer'])
return Customer
# run function
Product = my_func(df, 'Product')
ModelName= my_func(df, 'ModelName')
You can define the regex as a string, adding there the column name from a variable. Finally passing that regex expression to re.search:
col_name = "Customer"
my_regex = r"('+re.escape(col_name)+'=>).*?(,)"
Customer_data = []
for i in range(0, len(df)):
try:
Customer = (re.search(my_regex, df[i]).group(0).split('=>')[1].replace('"','').replace(',',''))
except:
Customer = ''
Customer_data.append(Customer)
Customer = pd.DataFrame(Customer_data.append, columns = ['Customer'])

Django keep one element by group and then use property on this queryset

I have a model like this one:
class Extension(models.Model):
name = models.CharField(max_length=32)
version = models.CharField(max_length=16)
#property
def path(self):
return something
I would like to get an Extension queryset containing only the last version for each name and then get a tuple (name, path) for each of these last recent Extension.
I tried
latests = Extension.objects.values('name').annotate(last=Max('version'))
but it gave me a dict without the properties access
How can i do that?
here's one way you could do it:
latests = Extension.objects.values('name').annotate(Max('version'))
q_statement = Q()
for pair in latests:
q_statement |= (Q(name=pair['name']) & Q(version=pair['version__max']))
extensions = Extension.objects.filter(q_statement)

get all from table django not only __str__(self)

models.py
class club(models.Model):
name = models.CharField(max_length=30)
city = models.CharField(max_length=30)
premiere_leauge = models.BooleanField(default=False)
def __str__(self):
return self.name
Views.py
...
a = request.POST['club']
b = request.POST['city']
result = club.objects.all.get(name__exact=a, city__exact=b)
....
All is fine, however I believe result returns me:
def __str__(self):
return self.name
Whatsover, I would like an equivalent of 'SELECT * FROM APP_CLUB where name='something and city='something'; so i would be able to do further manipulation in django like:
if result[3] is True:
do_something()
As suggested in the offical documentation:
club.objects.filter(name='something')
It will return exactly the same as:
'SELECT * FROM APP_CLUB where name='something';
Example:
clubs = club.objects.filter(name__exact='something')
for club in clubs:
if club.premier_league:
do_something()
If you want to get only one club, then do it like this:
club = club.objects.get(name='something')
premier_league_value_of_club = club.premier_league
Use filter instead of get.
results = club.objects.filter(name__exact=a, city__exact=b)
You can then iterate over it to access all the model attributes like below
for result in results:
print result.name, result.city, result.premier_league
Also, according to PEP-8, you should name your class name should ideally be titlecase Club instead of lowercase club.
You're nearly there, I think you're missing the filter function here. You can use it like this :
a = request.POST['club']
b = request.POST['city']
result = club.objects.filter(name__exact=a, city__exact=b)
It will return you a query set with the actual database entries.
The __str__(self) function is used in transforming your query set entry into a string, whether you string-cast it or print it.
Then about this :
if result[3] is True:
do_something()
I don't get well what you mean about this, but if 3 is the id of the entry in the database, you then can do this :
if result.get(id=3).premiere_leauge:
do_something()
But you might want to check if the entry with the id exists first to avoid errors :
if result.filter(id=3).exists() and result.get(id=3).premiere_leauge:
do_something()
You should modify you query as shown below
result = club.objects.filter(name__exact=a, city__exact=b)
Good Luck !!

Django-tables2: Provide a list of dictionary, how to generate a column for each dictionary entry

I know if we have a model class, we can make a generate table and use:
class Meta:
model = MyModel
To display every field.
Now say if I have a list of dictionaries, instead of model, is there a similar way to do so?
(Since there are so many different dictionaries, which might be dynamically created, I don't wanna create a customized one each time :-))
You can create your own class that inherits from Table and define the fields you want there.
class JsonTable(Table):
json_key_1 = Column()
json_key_2 = Column()
Also django tables2 have a fields attribute but you can't use it if your data is an array of dicts.
I've been doing this too, here's a rough sketch.
Piggy-backing on top of django_tables2 is miles ahead of rolling your own!
Plus, I hook up the results to jquery FooTable plugin.
import django_tables2 as tables
counter = 0
def generate(li_dict):
#unique classname.
global counter
counter += 1
table_classname = "MyTableClass%s" % (counter)
class Meta:
#ahhh... Bootstrap
attrs = {"class": "table table-striped"}
#generate a class dynamically
cls = type(table_classname,(tables.Table,),dict(Meta=Meta))
#grab the first dict's keys
li = li_dict[0].keys()
for colname in li:
column = tables.Column()
cls.base_columns[colname] = column
return cls
#now, to make use of it...
li_dict = [dict(a=11,b=12,c=13),dict(a=21,b=22,c=23)]
cls = generate(li_dict)
table = cls(li_dict)
# below didn't work, wanted a whole bunch of django setup done first.
# but I fairly confident it would...
print table.as_html()
>>>django.core.exceptions.ImproperlyConfigured: {% querystring %} requires django.core.context_processors.request to be in your settings.TEMPLATE_CONTEXT_PROCESSORS in order for the included template tags to function correctly.
#this did...
print "%s" % table
>>><django_tables2.tables.MyTableClass1 object at 0x1070e1090>
i am sorry for poor english :), but a think which can help, actually with this we can transforme a numpy (matrix) in a generic django table2. By the way, thanks Pyeret for your help.
def convert_array_list_dict(arr):
_list = []
for i in xrange(0, arr.shape[0]):
_list.append(dict(enumerate(arr[i,:])))
for i in xrange(0,len(_list)):
for key in _list[i].keys():
_list[i]["col_" + str(key)] = _list[i].pop(key)
return _list`
This function above convert numpy array to list of dict
counter = 0
def list_dict(dict_):
global counter
counter += 1
table_classname = "MyTableClass%s" % (counter)
class Meta:
attrs = {"class": "paleblue", 'width': '150%'}
cls = type(table_classname, (tables.Table,), dict(Meta=Meta))
list_ = dict_[0].keys()
for colname in list_:
column = tables.Column()
cls.base_columns[colname] = column
return cls
This code make a generic table...and
t = np.loadtxt(doc.document)
tab = convert_array_list_dict(t)
table = list_dict(tab)
table_content = table(tab)
RequestConfig(request, paginate={'per_page': 30}).configure(table_content)
return render(request,'app/snippets/upload_file.html',{'document':document,'table_content':table_content})
Above we can see how use all code...

Class design: Last Modified

My class:
class ManagementReview:
"""Class describing ManagementReview Object.
"""
# Class attributes
id = 0
Title = 'New Management Review Object'
fiscal_year = ''
region = ''
review_date = ''
date_completed = ''
prepared_by = ''
__goals = [] # List of <ManagementReviewGoals>.
__objectives = [] # List of <ManagementReviewObjetives>.
__actions = [] # List of <ManagementReviewActions>.
__deliverables = [] # List of <ManagementReviewDeliverable>.
__issues = [] # List of <ManagementReviewIssue>.
__created = ''
__created_by = ''
__modified = ''
__modified_by = ''
The __modified attribute is a datetime string in isoformat. I want that attribute to be automatically to be upated to datetime.now().isoformat() every time one of the other attributes is updated. For each of the other attributes I have a setter like:
def setObjectives(self,objectives):
mro = ManagementReviewObjective(args)
self.__objectives.append(mro)
So, is there an easier way to than to add a line like:
self.__modified = datetime.now().isoformat()
to every setter?
Thanks! :)
To update __modified when instance attributes are modified (as in your example of self.__objectives), you could override __setattr__.
For example, you could add this to your class:
def __setattr__(self, name, value):
# set the value like usual and then update the modified attribute too
self.__dict__[name] = value
self.__dict__['__modified'] = datetime.now().isoformat()
Perhaps adding a decorator before each setter?
If you have a method that commits the changes made to these attributes to a database (like a save() method or update_record() method. Something like that), you could just append the
self.__modified = datetime.now().isoformat()
just before its all committed, since thats the only time it really matters anyway.

Categories