Dynamic keyword with database value - python

I have a model like this:
class meter1(models.Model):
U1N = models.FloatField(default=0)
U2N = models.FloatField(default=0)
In my view (simplified) I want to set the value for the database dynamically:
def import_data:
dict = {"1":"U1N","2":"U2N",}
c = "1"
q = meter1()
q.eval('dict[c]') = "1"
q.save()
In real dict contains 60 items, and c changes every time in a for loop. The code in this example results in an error: NameError: name 'U1N' is not defined.
How do I dynamically set the keyword for q?

You can also dynamically build a dict from your dict (you shouldn't use a builtin name as identifier BTW) and pass it as kwargs to meter1() (you shouldn't use all-lowers as class names BTW). Oh and yes: you may want to have a look at modelmanager.create() too.
def import_data():
fieldmap = {"1":"U1N","2":"U2N",}
fieldindex = "1"
kw = {fieldmap[fieldindex]: 1.0}
# either:
q = Meter1(**kw)
q.save()
# or:
q = Meter1.objects.create(**kw)

You can use setattr to dynamically set attributes to the objects.

Related

Save and duplicate an instance in django

I have to define a function in order to duplicate an instance of my class Scenario.
I created an identical instance whose fields are identical except name and id, but when I save the new instance the original is deleted. Here is the code of the function:
def duplicate(scn):
attr_list = [field for field in Scenario._meta.get_fields() if isinstance(field,django.db.models.fields.Field)]
s = Scenario()
s.id = str(scn.id+10)
s.name='s_dup_of_' + scn.name
#print(Scenario.objects.all())
for a in attr_list:
if a.name!='name' and a.name!= 'id':
value = getattr(scn,a.name)
setattr(s,a.name,value)
#print(Scenario.objects.all())
#list_class = [Unit,HidroUnit,ThermalUnit,Arc,Flow,Fuel,Group,Loop,Machine,ModeVir,Node,Region,Reservoir,Solution,Station,Transitions,Tube]
list_class = [Unit,HidroUnit,ThermalUnit]
for myClass in list_class:
instance_list = myClass.objects.filter(scenario=scn)
attr_list = [field for field in myClass._meta.get_fields() if isinstance(field,django.db.models.fields.Field)]
for instance in instance_list:
inst_new = myClass()
for a in attr_list:
if a.name!='temporalobject_ptr':
value = getattr(instance,a.name)
setattr(inst_new,a.name,value)
inst_new.save()
#print(Scenario.objects.all())
s.save()
#print(Scenario.objects.all())
return None
For example, if I want to duplicate the scenario called s1 and to create the scenario s_dup_s1, and if I reproduce all lines of my duplicate function, then after I write s_dup_s1.save() the old instance s1 is deleted.
What can I do if I want s1 and s1_sup_s1 at the same time?
This is what happens when I run the code:
This doesn't work either:
Here's an easy hack to duplicate your instance:
You can rewrite your duplicate function as follows:
def duplicate(instance):
duplicate = Scenario.objects.get(pk=instance.pk)
duplicate.pk = None
duplicate.save()
return duplicate
This way your initial instance is preserved and you can do whatever you want with it. And, the function duplicate creates a duplicate of your instance, saves it and returns it.
Finally I find a solution. If you want to duplicate an instance s1 you have to set a new name and a new id and save it:
s1.id = scn.id+1
s1.name = scn.name + '_dup'
s1.save()
Of this way you will have both s1 and s1_dup.
The next works:
def duplicate(scn):
scn.id = scn.id+1
scn.name = scn.name + '_dup'
scn.save()
n = Scenario.objects.all().count()
s_new = Scenario.objects.all()[n-1]
list_class = [Unit,HidroUnit,ThermalUnit]
for myClass in list_class:
instance_list = myClass.objects.filter(scenario=scn)
attr_list = [field for field in myClass._meta.get_fields() if isinstance(field,django.db.models.fields.Field)]
for instance in instance_list:
instance.scenario = s_new
instance.num = instance.num + 1
instance.save()
return None

Where do I assign a variable in order for it to be used in a function (inside a class)?

I'm creating a class using tkinter that lets you input multiple product's information, and I've got everything else down except for changing the entry fields to set values for the other products.
I'm putting the product changeover process into a function called saveVars which saves the entered information to the specific product variable, and then clears the entry fields, and switches the saveVars to be performed on the second product variable.
i = 1
def saveVars(i):
if i == 1:
product1.productName = self.prodName.get()
product1.productID = self.prodID.get()
product1.productSize = self.prodSize.get()
product1.productPrice = self.prodPrice.get()
product1.productQuant = self.quantity.get()
elif i == 2:
product2.productName = self.prodName.get()
product2.productName = self.prodID.get()
product2.productSize = self.prodSize.get()
product2.productPrice = self.prodPrice.get()
product2.productQuant = self.quantity.get()
elif i == 3:
product3.productName = self.prodName.get()
product3.productName = self.prodID.get()
product3.productSize = self.prodSize.get()
product3.productPrice = self.prodPrice.get()
product3.productQuant = self.quantity.get()
newProduct()
i += 1
return i
I'm expecting to get it to switch the variable the entries are being saved to to the next respective product based on a +1 function, I'm having it return the i function as the new i, which should then save the entries to the next variable in the process, but it keeps telling me that I'm 'missing 1 required positional argument: 'i'
You are trying to call the function without parameter as the command attribute does not take parameters just the name of the function.
To pass parameters you could use partial form functools package
import statement :
from functools import partial
your call to function would look like :
addItemButton = Button(window, text = "Add to Cart", fg='black',bg='yellow',width = 10, height = 2, command = partial(saveVars,i)) addItemButton.place(x=800,y=375)
You can set the inital value to i in your class using a global variable instead of declaring it outside the class. You can save it anywhere you wish and pass it while calling the funtion.
It seems like you are calling saveVars without the parameter in some case. To prevent this you can set a default value of i, eg.
def saveVars(i=0)

How to make nested enum also have value

Consider the following code example:
from enum import Enum
class Location(Enum):
Outside = 'outside'
Inside = 'inside'
class Inside(Enum): # TypeError for conflicting names
Downstairs = 'downstairs'
Upstairs = 'upstairs'
How do I make Inside have the value 'inside' whilst also being a nested enum for accessing Downstairs and Upstairs?
Desired input:
print(Location.Inside)
print(Location.Inside.value)
print(Location.Inside.Downstairs)
print(Location.Inside.Downstairs.value)
Desired output:
Location.Inside
inside
Location.Inside.Downstairs
downstairs
UPDATE 1:
Some more context to my specific problem:
class Location(Enum):
Outside = 'outside'
Inside = 'inside'
class Inside(Enum): # TypeError for conflicting names
Downstairs = 'downstairs'
Upstairs = 'upstairs'
class Human:
def __init__(self, location):
self.location = location
def getLocationFromAPI():
# this function returns either 'inside' or 'outside'
# make calls to external API
return location # return location from api in str
def whereInside(human):
if human.location != Location.Inside:
return None
# here goes logic that determines if human is downstairs or upstairs
return locationInside # return either Location.Downstairs or Location.Upstairs
location_str = getLocationFromAPI() # will return 'inside' or 'outside'
location = Location(location_str) # make Enum
human = Human(location) # create human with basic location
if human.location == Location.Inside:
where_inside = whereInside(human)
human.location = where_inside # update location to be more precise
The problem is when I create the Human object I only know of a basic location, as in 'inside' or 'outside'. Only after that can I update the location to be more precise.
You can accomplish this by embedding an enum.Enum inside another like so: (just watch out for names conflicting)
from enum import Enum
class _Inside(Enum):
Downstairs = 'downstairs'
Upstairs = 'upstairs'
class Location(Enum):
Outside = 'outside'
Inside = _Inside
print(Location.Inside.value.Downstairs.value)
downstairs
it may be a bit late and the one who asked the question is no longer necessary, but I leave it here in case someone wants to take a look at it, and even if it has already been validated as one, although the same comment that it is not completely complete .
But I have been thinking about it and in the end I have solved it by looking at the same documentation XD.
You cannot extend classes of Enums, but you can extend methods, I have followed this way and the only thing I have done has been to override the new and init methods, the use case can be modified, this is only to nest enumerators.
from enum import Enum
class SuperNestedEnum(Enum):
def __new__(cls, *args):
obj = object.__new__(cls)
value = None
# Normal Enumerator definition
if len(args) == 1:
value = args[0]
# Have a tuple of values, first de value and next the nested enum (I will set in __init__ method)
if len(args) == 2:
value = args[0]
if value:
obj._value_ = value
return obj
def __init__(self, name, nested=None):
# At this point you can set any attribute what you want
if nested:
# Check if is an Enumerator you can comment this if. if you want another object
if isinstance(nested, EnumMeta):
for enm in nested:
self.__setattr__(enm.name, enm)
class Homework(Enum):
Task = "5"
class Subjects(SuperNestedEnum):
Maths = "maths"
English = "english"
Physics = "nested", Homework
class School(SuperNestedEnum):
Name = "2"
Subjects = "subjects", Subjects
Ignore the use case because it doesn't make sense, it's just an example
>>> School.Name
<School.Name: '2'>
>>> School.Subjects
<School.Subjects: 'subjects'>
>>> School.Subjects.value
'subjects'
>>> School.Subjects.Maths
<Subjects.Maths: 'maths'>
>>> School.Subjects.Physics.value
'nested'
>>> School.Subjects.Physics.Task
<Homework.Task: '5'>
>>> School.Subjects.Physics.Task.value
'5'
If anyone has similar issues and just wants a simple solution for the topic without patching any functions or additional imports for enums containing strings, follow these steps:
Create the value enums, in your lower hierarchy, like:
class __private_enum1__(str, enum.Enum):
VAL11 = "abc"
VAL12 = "def"
class enum2(str, enum.Enum):
VAL21 = "123"
VAL22 = "456"
Create a base class (a container) for these enums. Where you can either import the enums classes or simply directly acccess the enums.
class myValues:
VAL11 = __private_enum1__.VAL11
VAL12 = __private_enum1__.VAL12
VALS2X = enum2
Then you can access your values by:
print(myValues.VAL11.value)
print(myValues.VAL2X.VAL21.value)
.value is not necessary here but it shows that you both access the string inside the enum for passing it to other functions but also the enum itself, which is pretty neat. So basically, first create the values, then the structure. That way you have a class but it provides you the basic functionality of enums and you can nest them as deep as you want to without further imports.

How to extract string values into object fields

I have this dictionary:
{"id":3,"name":"MySQL","description":"MySQL Database Server - Fedora 21 - medium","image":"","flavor":""}
And I have this object:
class Record():
id = None
name = None
description = None
image = None
flavor = None
How can I assign values from the dictionary to their corresponding class fields?
Take a dict object as the parameter of init function:
class Record(object):
def __init__(self,record_dict):
try:
self.id = record_dict['id']
self.name = record_dict['name']
self.description = record_dict['description']
self.image = record_dict['image']
self.flavor = record_dict['flavor']
except KeyError:
print 'KeyError'
def get_name(self):
return self.name
adict = {"id":3,"name":"MySQL","description":"MySQL Database Server - Fedora 21 - medium","image":"","flavor":""}
one_obj = Record(adict)
print one_obj
print one_obj.get_name()
output:
<__main__.Record object at 0x022E4C90>
MySQL
works for me...
You probably want something like this:
class Record:
def __init__(self, myDict):
self.id = myDict[“id”]
self.name = myDict[“name”]
self.description = myDict[“description”]
self.image = myDict[“image”]
self.flavor = myDict[“flavor”]
And call it:
rec = Record(myDict)
See here to understand the difference between class and instance variables.
Long story short, class variables have a single value for every instance of the class while instance variables values are unique to each instance.
A class variable is defined like this:
class myClass:
Classvar = ‘something’
An instance variable is defined like this:
class myClass:
def __init__():
Self.instanceVar = ‘something else’
This has already been answered here:
Convert Python dict to object?
My favorite method is this one: x.__dict__.update(d)
You can assign them as follows, assuming your dictionary name is input
id = input['id']
name = input['name']
description = input['description']
image = input['image']
flavor = input['flavor']
Try this method in which you grab the attributes of the object:
r = Record()
attributes = [i for i in dir(r) if not i.startswith('_')]
Basically, there are a bunch of background attributes that contain a bunch of underscores. The dir method gets all the attributes and we create a list of the ones that we want. At this point:
# attributes = ['count', 'description', 'flavor', 'id', 'image', 'index', 'name']
So now we use __setattr__ to set the attributes we just grabbed according to the my_dict
for i in attributes:
r.__setattr__(i, my_dict[i])
See the code run online here.
When you create the Record, pass in the dictionary. Then map the key to the value.
Another simple method, see the code here
r = Record()
for k, v in my_dict.items():
exec('r.' + k + '="' + str(v) + '"')

Dynamic variable name in python

I'd like to call a query with a field name filter that I wont know before run time... Not sure how to construct the variable name ...Or maybe I am tired.
field_name = funct()
locations = Locations.objects.filter(field_name__lte=arg1)
where if funct() returns name would equal to
locations = Locations.objects.filter(name__lte=arg1)
Not sure how to do that ...
You can create a dictionary, set the parameters and pass this to the function by unpacking the dictionary as keyword arguments:
field_name = funct()
params = {field_name + '__lte': arg1, # field_name should still contain string
'some_other_field_name': arg2}
locations = Locations.objects.filter(**params)
# is the same as (assuming field_name = 'some_name'):
# Locations.objects.filter(some_name__lte=arg1, some_other_field_name=arg2)

Categories

Resources