Copy Model Object From a Model To Another In Django

后端 未结 5 768
挽巷
挽巷 2021-01-03 00:41

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

class Profile(mo         


        
相关标签:
5条回答
  • 2021-01-03 01:22

    I'm having a tough time understanding what you wrote above, consequently I'm not 100% certain if this will work, but what I think I would do is something like this, if I'm understanding you right:

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

    and then

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

    But I think this looks more like poor database design then anything, without seeing the entire model1 I can't be certain. But, in any event, I'm not sure why you want to do that anyway, when you can simply use inheritance at the model level, or something else to get the same behavior.

    0 讨论(0)
  • 2021-01-03 01:23

    This is how I do it (note: this is in Python3, you might need to change things - get rid of the dictionary comprehension - if you are using 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 讨论(0)
  • 2021-01-03 01:26

    So, if I'm interpreting your problem correctly, you have an old model (Profile), and you're trying to replace it with the new model SurveyProfile. Given the circumstances, you may want to consider using a database migration tool like South in the long run. For now, you can run a 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()
    

    Using South

    If this project needs to be maintained and updated in the long term, I would highly recommend using a database migration package like South, which will let you modify fields on a Model, and migrate your database painlessly.

    For example, you suggest that your original model had too many ManyToManyFields present. With South, you:

    1. Delete the fields from the model.
    2. Auto-generate a schema migration.
    3. Apply the migration.

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

    0 讨论(0)
  • 2021-01-03 01:30

    deepcopy etc won't work because the classes/Models are different.

    If you're certain that SurveyProfile has the all of the fields present in Profile*, this should work (not tested it):

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

    * (in which case, I suggest you make an abstract ProfileBase class and inherit that as a concrete class for Profile and SurveyProfile, but that doesn't affect what I've put above)

    0 讨论(0)
  • 2021-01-03 01:39

    Here's the function I've been using, it builds on model_to_dict. Model_to_dict just returns the ids of foreign keys + not their instances, so for those 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)
    
    0 讨论(0)
提交回复
热议问题