user9450057
user9450057

Reputation:

Creating records by model

Suppose I have such models:

class Recipe (models.Model):
    par_recipe = models.CharField(max_length=200)

class Line (models.Model):
    par_machine = models.CharField(max_length=200)

class Measurements (models.Model):
    par_value = models.IntegerField(default=0)
    id_line = models.ForeignKey(Line)
    id_recipe = models.ForeignKey(Recipe)

Do I understand correctly that in this way I have a 1: 1 relationship, and adding entries ids will be automatically created id_line,id_recipe.

I will add for example:

for row in ws.iter_rows(row_offset=1):
        recipe =Recipe()
        line = line()
        measurements = Measurements()

        recipe.par_recipe = row[1].value
        line.par_machine = row[2].value
        measurements.par_value = row[8].value

And the small question about measurements was conceived that all secondary keys should go to it, now it is implemented correctly?

Upvotes: 2

Views: 46

Answers (2)

Sina Khelil
Sina Khelil

Reputation: 1991

It is not quite like that, you would have to tie them together:

for row in ws.iter_rows(row_offset=1):
    recipe =Recipe.objects.create(par_recipe=row[1].value)
    line = Line.objects.create(par_machine=row[2].value)
    measurements = Measurements.objects.create(
        par_value=row[8].value, 
        id_line=line, 
        id_recipe=recipe
    )

None of this is db optimized, you could use transactions to optimize the db writes.

You could make it faster if there are a lot of rows by using transactions:

from django.db import transaction

with transaction.atomic():
    for row in ws.iter_rows(row_offset=1):
        recipe =Recipe.objects.create(par_recipe=row[1].value)
        line = Line.objects.create(par_machine=row[2].value)
        measurements = Measurements.objects.create(
            par_value=row[8].value, 
            id_line=line, 
            id_recipe=recipe
        )

This would create a transaction and write one instead of each time. But it will also fail the whole transaction on an error.

see Django Database Transactions

You could get more creative by counting the number of records and writing every 1000 records for example by:

from django.db import transaction

with transaction.atomic():
    for idx, row in enumerate(ws.iter_rows(row_offset=1)):
        recipe =Recipe.objects.create(par_recipe=row[1].value)
        line = Line.objects.create(par_machine=row[2].value)
        measurements = Measurements.objects.create(
            par_value=row[8].value, 
            id_line=line, 
            id_recipe=recipe
        )
        # every 1000 records, commmit the transaction
        if idx % 1000 == 0:
           transaction.commit()

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476557

Do I understand correctly that in this way I have a 1: 1 relationship, and adding entries ids will be automatically created id_line,id_recipe.

The relations will not link to the previously constructed objects, that would also be quite unsafe since a small change to the code fragment, could result in a totally different way of linking elements together.

Furthermore a ForeignKey is a many-to-one relation: multiple Measurements objects can refer to the same Recipe object.

You need to do this manually, for example:

for row in ws.iter_rows(row_offset=1):
    recipe = Recipe.objects.create(par_recipe=row[1].value)
    line = Line.objects.create(par_machine=row[2].value)
    measurements = Measurements.objects.create(
        par_value=row[8].value,
        id_line=line,
        id_recipe=recipe
    )

Note that a ForeignKey refers to the objects, not to the primary key value, so you probably want to rename your ForeignKeys. A model typically has a singular name, so Measurement instead of Measurements:

class Measurement(models.Model):
    par_value = models.IntegerField(default=0)
    line = models.ForeignKey(Line, on_delete=models.CASCADE)
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)

Upvotes: 1

Related Questions