Save and duplicate an instance in django - python

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

Related

Adding a new object to a class with user-input(input) in python

I am trying to add new objects to a class(emne) but the new instances of the class needs to be created using user input. So i need a way to be able to chose the name for the object and set some of the values of the objects with user input.
I have already tried to create a function that passes the value of the user input into a x = emner(x) to create it but it only returns:
AttributeError: 'str' object has no attribute 'fagKode'
so i think my issue is that the value of the input is created as a string so that it is not understood as a way to create the function
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne():
nyttEmne = input("test:")
nyttEmne=Emne(nyttEmne)
expected result is that the code creates a new instance of the class.
If by choosing a name you mean your fagKode attribute, what you need is:
fagKode = input('Enter code: ')
Emne(fagKode)
You're adding the instances of Enme to the list in the constructor, so you don't need to save them to a variable.
Alternatively, you can handle that in the function:
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
def leggTilEmne():
nyttEmne = input("test:")
enme.append(Emne(nyttEmne))
I'm not sure what exactly you are asking, since you haven't responded to the comments. So,
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne(self, value): # <--- is this what you want
self.nyttEmne= Emne(value)
This is an example of when to use a class method. __init__ should not be appending to a global variable, though. Either 1) have the class method append to a class attribute, or 2) have it return the object and let the caller maintain a global list.
emne = []
class Emne:
emne = []
def __init__(self, fag_kode):
self.fag_kode = fag_kode
self.karakter = ""
#classmethod
def legg_til_emne_1(cls):
nytt_emne = input("test:")
cls.emne.append(cls(nytt_emne))
#classmethod
def legg_til_emne_2(cls):
nyttEmne = input("test:")
return cls(nyttEmne)
Emne.legg_til_emne_1() # Add to Emne.emne
e = Emne.legg_til_emne_2()
emne.append(e)

list of objects python

I am trying to print a list of python objects that contain a list as a property and i am having some unexpected results:
here is my code:
class video(object):
name = ''
url = ''
class topic(object):
topicName = ''
listOfVideo = []
def addVideo(self,videoToAdd):
self.listOfVideo.append(videoToAdd)
def getTopic(self):
return self.topicName
def getListOfVideo(self):
return self.listOfVideo
topic1 = topic()
topic1.topicName = 'topic1'
video1 = video()
video1.name = 'VideoName1'
video1.url = 'VideoURL1'
video2 = video()
video2.name = 'VideoName2'
video2.url = 'VideoURL2'
topic1.addVideo(video1)
topic1.addVideo(video2)
topic2 = topic()
topic2.topicName = 'topic2'
video3 = video()
video3.name = 'VideoName3'
video3.url = 'VideoURL3'
video4 = video()
video4.name = 'VideoName4'
video4.url = 'VideoURL4'
topic2.addVideo(video3)
topic2.addVideo(video4)
topicsList = []
topicsList.append(topic1)
topicsList.append(topic2)
for topicCurrent in topicsList:
print(topicCurrent.topicName)
for video in topicCurrent.getListOfVideo():
print(video.name)
print(video.url)
What I expect to get is this:
topic1
VideoName1
VideoURL1
VideoName2
VideoURL2
topic2
VideoName3
VideoURL3
VideoName4
VideoURL4
but what I actually get is this:
topic1
VideoName1
VideoURL1
VideoName2
VideoURL2
VideoName3
VideoURL3
VideoName4
VideoURL4
topic2
VideoName1
VideoURL1
VideoName2
VideoURL2
VideoName3
VideoURL3
VideoName4
VideoURL4
Why? I want to iterate over my list of topics and print out each video in each topic, but for each topic it prints out all videos???
What is going on here?
You have created class variables instead of instance variables, which are different for each instance object. Define your class as follows:
class topic(object):
def __init__(self):
self.topicName = ''
self.listOfVideo = []
def addVideo(self,videoToAdd):
self.listOfVideo.append(videoToAdd)
def getTopic(self):
return self.topicName
def getListOfVideo(self):
return self.listOfVideo
From Python Tutorial:
Instance variables are for data unique to each instance and class
variables are for attributes and methods shared by all instances of
the class.
EDIT:
One more important thing to consider is that why only listOfVideo was common for all instances but not topicName. It is because list's are mutable objects while string's are immutable.
So any changes made to listOfVideo are common for all instances, i.e., they still refer to listOfVideo defined in the topic namespace.
However when you do topic1.topicName = 'topic1', you create a new variable topicName within topic1 namespace, which overrides the topicName found in topic(class) namespace. You can confirm it by printing the value topic.topicName, which you will find to be an empty string, i.e., ''.

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 keyword with database value

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.

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