Copy model object from model to another in Django

I need to simulate. I want to copy a model object from a model to another: Model2 is a copy of Model1 (these models have too many m2m fields) Model1:

class Profile(models.Model): user = models.OneToOneField(User) car = models.ManyToManyField(Car) job = models.ManyToManyField(Job) . . 

This is a survey application. I want to save the user profile when he visits the poll (because he can edit the profile after the poll) I created another model to save the user profile when he does the poll (Im not sure if this is the right way)

 class SurveyProfile(models.Model): user = models.OneToOneField(SurveyUser) #this is another model that takes survey users car = models.ManyToManyField(Car) job = models.ManyToManyField(Job) 

How to copy user profile from profile in SurveyProfile.

Thanks in advance

+6
source share
5 answers

deepcopy etc. will not work because classes / models are different.

If you are sure that SurveyProfile has all the fields present in Profile *, this should work (not tested):

 for field in instance_of_model_a._meta.fields: if field.name == 'id': continue # don't want to clone the ID setattr(instance_of_model_b, field.name, getattr(instance_of_model_a, field.name)) instance_of_model_b.save() 

* (in this case, I suggest you create an abstract ProfileBase class and inherit it as a concrete class for Profile and SurveyProfile , but this does not affect the fact that I have SurveyProfile above)

+9
source

It's hard for me to understand what you wrote above, so I'm not 100% sure if this will work, but what I think I will do is something like this if I understand you correctly: / p>

 class Model2Form(ModelForm): class Meta: model = models.Model2 

and then

 f = Model2Form(**m1.__dict__) if f.is_valid(): f.save() 

But I think it looks more like a poor database design than anything without seeing the whole model1, I can’t be sure. But, in any case, I'm not sure why you want to do this anyway, when you can just use inheritance at the model level or something else to get the same behavior.

+3
source

Here, the function I used is based on model_to_dict. Model_to_dict simply returns the identifiers of foreign keys + not their instances, so for those who I replace them with the model itself.

 def update_model(src, dest): """ Update one model with the content of another. When it comes to Foreign Keys, they need to be encoded using models and not the IDs as returned from model_to_dict. :param src: Source model instance. :param dest: Destination model instance. """ src_dict = model_to_dict(src, exclude="id") for k, v in src_dict.iteritems(): if isinstance(v, long): m = getattr(src, k, None) if isinstance(m, models.Model): setattr(dest, k, m) continue setattr(dest, k, v) 
+2
source

Here's how I do it (note: this is in Python3, you may need to change something - get rid of the understanding of the dictionary - if you use Python 2):

 def copy_instance_kwargs(src, exclude_pk=True, excludes=[]): """ Generate a copy of a model using model_to_dict, then make sure that all the FK references are actually proper FK instances. Basically, we return a set of kwargs that may be used to create a new instance of the same model - or copy from one model to another. The resulting dictionary may be used to create a new instance, like so: src_dict = copy_instance_kwargs(my_instance) ModelClass(**src_dict).save() :param src: Instance to copy :param exclude_pk: Exclude the PK of the model, to ensure new records are copies. :param excludes: A list of fields to exclude (must be a mutable iterable) from the copy. (date_modified, for example) """ # Exclude the PK of the model, since we probably want to make a copy. if exclude_pk: excludes.append(src._meta.pk.attname) src_dict = model_to_dict(src, exclude=excludes) fks={k: getattr(src, k) for k in src_dict.keys() if isinstance(getattr(src, k, None), models.Model) } src_dict.update(fks) return src_dict 
0
source

So, if I interpret your problem correctly, you have an old Model ( Profile ), and you are trying to replace it with a new SurveyProfile model. Given the circumstances, you might consider using a database migration tool such as South in the long run. At the moment, you can run the script in the Django shell ( manage.py shell ):

 from yourappname.models import * for profile in Profile.objects.all(): survey_profile = SurveyProfile() # Assuming SurveyUser has user = ForeignKey(User)... survey_profile.user = SurveyUser.objects.get(user=profile.user) survey_profile.car = profile.car survey_profile.job = profile.job survey_profile.save() 

Use of the south

If this project needs to be maintained and updated in the long term, I highly recommend using a database migration package, such as South , which will allow you to change the fields in the model and transfer your database painlessly.

For example, you assume there were too many ManyToManyField in your original model. With the South, you:

  • Remove fields from the model.
  • Automatically create schema migration.
  • Apply migration.

This allows you to reuse all of your old code without changing the model names or deleting with the database.

-1
source

Source: https://habr.com/ru/post/917012/


All Articles