keera
keera

Reputation: 1

Function to copy fields from a model to another model in django

I want to merge 2 different models with different but overlapping fields.

I try to write a function that copy the fields with its data from model A to model B.

def create_field():
    old = DetailItem.objects.all()
    new = CrawlItem.objects.all()

    for item in old:
        c = CrawlItem.objects.get(title=item.title, description=item.description, link=item.link, cpvcode=item.cpvcode, postalcode=item.postalcode  )
        c.save()

and i don't know whereis the mistake. I want to have a model that contains the data from the old model and some new fields.

Here is my code for the two models:

class DetailItem(Base): 

  title  = models.CharField(max_length=500)
  description = models.CharField(max_length=20000)
  link = models.URLField()
  cpvcode = models.ManyToManyField('CPVCode',related_name='cpv')
  postalcode = models.ForeignKey('PostalCode',on_delete=models.SET_NULL,null=True,blank=True,related_name='postal')

def __str__(self):
    return self.title

class CrawlItem(Base):

  guid = models.CharField( primary_key=True, max_length=500)
  title = models.CharField(max_length=500)
  link = models.URLField()
  description = models.CharField(max_length=2000)
  pubdate = models.DateTimeField()
  detail = models.ForeignKey('DetailItem',on_delete=models.SET_NULL,null=True,blank=True,related_name='crawldetail')

def __str__(self):
    return str(self.title)

This is what I want to get:

class CrawlItem(Base):
  guid = ...
  title = ...
  link = ...
  cpvcodes = ...
  postalcode = ...
  pubdate = ...
  vergabestelle = ...
  vergabeart = ...
  anmeldefrist = ...
  description = ...

Any ideas how to get there are highly appreciated!

Upvotes: 0

Views: 592

Answers (2)

dirkgroten
dirkgroten

Reputation: 20672

It's not entirely clear which objects already exist in your database, and when you consider two objects to be "equal". Assuming a CrawlItem is "equal" to a "DetailItem" when title, description and link are the same, then you can use the update_or_create function like this:

for item in old:
    CrawlItem.objects.update_or_create(
        # if matching, existing item updated, otherwise new item created
        title=item.title, description=item.description, link=item.link,
        defaults = {'cpvcode': item.cpvcode, 'postalcode': item.postalcode}
    )

Alternatively, if the two models are linked with the fk as shown in your models (and you want to remove it later on), then you don't even need to check for "equal" objects because you already have all the related ones (assuming title, description and link are already equal):

for item in old:
    item.crawldetail.all().update(cpvcode=item.cpvcode, postalcode=item.postalcode)

Upvotes: 1

Gabriel
Gabriel

Reputation: 1149

in your for statement you are just trying to select de CrawlItem with the same values as DetailItem using the get queryset method.

if you want to create a CrawlItem you should use the create method (docs here -> https://docs.djangoproject.com/en/2.2/ref/models/querysets/#create)

c = CrawlItem.objects.create(title=item.title, ..., postalcode=item.postalcode)

it will be created when create() is called, so, you don't need to save it afterwards, c is set to the newly created object.

For performance reasons you can use bulk_create() method as follows (docs here -> https://docs.djangoproject.com/en/2.2/ref/models/querysets/#bulk-create)

new_crawlitems = []
for item in old:
    new_crawlitems.append(CrawlItem(title=item.title, description=item.description, link=item.link, cpvcode=item.cpvcode, postalcode=item.postalcode)
CrawlItem.objects.bulk_create(new_crawlitems)

Hope this helps and put you on the right direction.

G.

Upvotes: 0

Related Questions