Aamu
Aamu

Reputation: 3611

How to copy an object from one model to another model

Each user has many albums, and each album has its many photos. And each user has one set background image to hold its many images. Similarly, a user has one set of profile picture to hold its many images.

These are my models:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    permanent_address = models.TextField()
    temporary_address = models.TextField()
    profile_pic = models.ForeignKey(ProfilePicture)
    background_pic = models.ForeignKey(BackgroundImage)


class Album(models.Model):
    user = models.ForeignKey(User)
    name = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)


class Photo(models.Model):
    album = models.ForeignKey(Album, default=3)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)


class BackgroundImage(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)


class ProfilePicture(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

Eg: I tried doing this: to let the user copy one image from ProfilePicture to Background Image, but didn't work:

# Get the user
>>>m = User.objects.get(username='m')

# Get its set of Profile pictures
>>>m_pro_set = m.profilepicture_set.all()
>>>m_pro_set
[<ProfilePicture: pro_mik>]

# Get its set of Background images
>>>m_back_set = m.backgroundimage_set.all()
>>>m_back_set
[<BackgroundImage: bg_mik>]

# Get an image object from Profile picture of the user
>>>m_pro_1 = m.profilepicture_set.get(id=2)
>>>m_pro_1
<ProfilePicture: pro_mik>

# Get an image object from Background image of the user
>>>m_back_1 = m.backgroundimage_set.get(id=2)
>>>m_back_1
<BackgroundImage: bg_mik>

# So, I tried to copy one image from BackgroundImage of a user to ProfilePicture

>>>m_pro_set.objects.create(m_back_1)

    File "<console>", line 1, object has attribute 'objects'
AttributeError: 'QuerySet' object has no attribute 'objects'

So my question is, how to copy an objects from one model to another? Any advice will be much appreciated.

Upvotes: 3

Views: 8389

Answers (1)

Tim Edgar
Tim Edgar

Reputation: 2143

You'll need to copy the properties of one object to another object. create is used when you want to create a new instance, not when you want to update a specific instance.

m_pro = m_pro_set[0] # m_pro_set is a list and need to get the specific instance
m_pro.image = m_back_1.image
m_pro.caption = m_back_1.caption
m_pro.pub_date = m_back_1.pub_date
m_pro.save()

Alternatively you can create a method on ProfilePicture if this is a common operation to contain this functionality.

class ProfilePicture(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

    def update(self, bg_img):
        self.image = bg_img.image
        self.caption = bg_img.caption
        self.pub_date = bg_img.pub_date
        self.save()

So you would just need to call m_pro_1.update(m_back_1) if we wanted to make m_pro_1 have the same properties as m_back_1

Also, if you wanted to create a new instance, I'd suggest using a classmethod like the following

class ProfilePicture(models.Model):
    ...

    @classmethod
    def create_from_bg(cls, bg_img):
        img = cls(user=bg_img.user, image=bg_img.image, caption=bg_img.caption, pub_date=bg_img.pub_date)
        img.save()
        return img

    @classmethod
    def create_from_photo(cls, photo):
        img = cls(user=photo.album.user, image=photo.image, caption=photo.caption, pub_date=photo.pub_date)
        img.save()
        return img

This creates a new ProfilePicture and is used: profile_pic = ProfilePicture.create_from_bg(m_back_1)

Upvotes: 4

Related Questions