Rmartin
Rmartin

Reputation: 243

Django model instance from foreign key

I am reading Excel using xlrd. One of the columns has the Bank name, which is linked to vehicle model via Foreign Key. When xlrd finishes reading a row, it should save that record to vehicle table. However getting the actual pk value and error that Vehicles.bank must a Banks instance.

After checking dozens of questions related to this issue, I found this one the most similar one, but still I am not getting the expected result.

The relevant Vehicle model section is as follows:

class Vehicles(models.Model):
    stock = models.CharField(max_length=10, blank=False, db_index=True)
    vin = models.CharField(max_length=17, blank=False, db_index=True)
    sold = models.DateField(blank=True, null=True, db_index=True)
    origin = models.CharField(max_length=10, blank=False, db_index=True)
    bank = models.ForeignKey('banks.Banks', db_column='bank', null=True)

I am using python 2.7, django 1.5.4 and Postgresql 9.2.5. Dbshell utility does show that banks table has a Foreign contraint referring to vehicles table, via banks(id).

Since I am not using a form for this particular part, I think it does not matter whether I use a ModelForm or not.

Current scenario: Excel file has FBANK as the cell value. There is an existing record in banks table that contains FBANK in its name column, id=2. The python line is:

def bank(value):
    return Banks.objects.get(name=value).id

With the above line, error is: Cannot assign "2": "Vehicles.bank" must be a "Banks" instance.

If I remove the ".id" at the end, error is then: Banks matching query does not exist.

Appreciate your help. Ricardo

Upvotes: 1

Views: 2904

Answers (2)

nickzam
nickzam

Reputation: 813

When saving Vehicle you need to pass Banks instance with corresponding bank name. See example, I suppose that you have all data in corresponding cells from 0 to 4, replace with your own cells numbers:

def get_bank_instance(bank_name):
    try:
        bank = Banks.objects.get(name=bank_name)
    except Banks.DoesNotExist:
        return None
    return bank

# reading excel file here, we have list of cells in a row
for cell in cells:
    bank = get_bank_instance(cell[4])
    if bank:
        # get other cells values to be saved in Vehicles
        stock, vin, sold, origin = cell[0], cell[1], cell[2], cell[3]
        Vehicles.create(bank=bank, stock=stock, vin=vin, sold=sold, origin=origin)

You also can create save instance of Vehicles passing bank id directly:

b_id = Banks.objects.get(name=bank_name).id
Vehicles.create(bank_id=b_id, stock=stock, vin=vin, sold=sold, origin=origin)

Update: create() is a built-in model method to create and save into database model instance. If you are asking about "Add a classmethod on the model class" in Django docs, this is not the case, because you are just using built-in method for the model. For some cases you can use custom method for creating new models, but I would do so if I had to pass a lot of default attributes for the new instance.

Also, it's possible to create and save new model instance by using save():

bank_instance = Banks.objects.get(name=bank_name)
vehicle = Vehicles()
vehicle.bank = bank_instance
vehicle.stock = stock
vehicle.vin = vin
vehicle.sold = sold
vehicle.origin = origin
# without save() data will not be saved to db!
vehicle.save()

It's quite long and you always need to remember to call .save(), so it's a good idea to use .create()

Upvotes: 1

Dominic Santos
Dominic Santos

Reputation: 1960

You should be returning a Banks instance when you want to assign it to a Vehicle model instance; so you should not have the .id part at the end of the return value for your bank() method.

Secondly, if it says that it isn't finding the Banks instance, then you should check the value of your value parameter to see what it is and try to manually do a Banks.objects.get from your database. If it can't be found then there is probably another reason for this other than using the Django ORM incorrectly.

When you are assigning instances to other instances in Django, for example setting the Bank for a Vehicle it must be an instance of the model and not the id or pk value of model; this is stated in the other StackOverflow question that you reference in your question.

Upvotes: 0

Related Questions