thehumaneraser
thehumaneraser

Reputation: 620

Why am I getting 'Foreign Key Mismatch' when trying to save a model form in Django?

I am trying to save an instance of a modelform in Django. I have setup a template to input information to the form and a view to handle the save. The form validates fine, but when trying to save it generates a foreigkey mismatch error. What am I doing wrong here?

I am running Django 2.0.0. I have already tried adding and removing the primary_key option without any luck and deleting my sqlite database, clearing all pycache, and migrating again. The problem persists.

#models.py
from django.db import models
import uuid
from users.models import Company, CustomUser
from delivery import settings

class Location(models.Model):
    location_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    address = models.CharField(max_length = 120)
    date_added = models.DateField(auto_now_add = True)

class Shipment(models.Model):
    date_created = models.DateField(auto_now_add=True)
    sender_company = models.ForeignKey(Company, on_delete = models.PROTECT, related_name='sender')
    receiver_company = models.ForeignKey(Company, on_delete = models.PROTECT, related_name='receiver')
    origin = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default = 'Location no longer active.', related_name='origin')
    destination = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default = 'DESTINATION UNKNOWN', related_name='destination')
    expected_arrival = models.DateField()
    weight = models.FloatField()
    current_handler = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.SET_DEFAULT, default = 'UNKNOWN')
    shipment_id = models.UUIDField(unique=True, primary_key = True, default=uuid.uuid4, editable=False)
#forms.py
from django import forms
from .models import Location, Shipment

class LocationRegisterForm(forms.ModelForm):

    class Meta:
        model = Location
        fields = '__all__'      

class CreateShipment(forms.ModelForm):

    class Meta:
        model = Shipment
        exclude = ['current_handler', 'shipment_id']

    def clean_expected_arrival(self):
        expected_arrival = self.cleaned_data['expected_arrival']
        date_created = self.cleaned_data['date_created']
        if expected_arrival < date_created:
            raise ValidationError('Expected arrival date cannot be in the past.')
        return expected_arrival
#views.py
from django.shortcuts import render, redirect
from .forms import CreateShipment, LocationRegisterForm
from users.permissions import group_required

@group_required('delivery_employee')
def new_shipment(request):
    if request.method == 'POST':
        form = CreateShipment(request.POST)
        if form.is_valid():
            temp_form = form.save(commit=False)
            current_user = request.user
            temp_form.current_handler = current_user
            temp_form.save()
            return redirect('dash-home')
        else:
            return render(request, 'shipments/new-shipment.html', {'form':form})
    form = CreateShipment()
    return render(request, 'shipments/new-shipment.html', {'form':form})

@group_required('delivery_employee')
def add_location(request):
    if request.method == 'POST':
        form = LocationRegisterForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('new-shipment')
        else:
            return render(request, 'shipments/location-register.html', {'form':form})
    form = LocationRegisterForm()
    return render(request, 'shipments/location-register.html', {'form':form})

I get the error message:

File "C:\Python34\lib\site-packages\django\db\backends\sqlite3\base.py", line 303, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: foreign key mismatch - "shipments_shipment" referencing "shipments_location"

Thank you!

Upvotes: 0

Views: 2092

Answers (1)

ipaleka
ipaleka

Reputation: 3957

Your origin and destination fields set default value to plain strings, their default values should be the default Location instances instead.

Create methods like get_default_origin and get_default_destination where you will return the existing records from the database. Assign those methods to default argument, like

origin = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default=self.get_default_origin, related_name='origin')
destination = models.ForeignKey(Location, on_delete = models.SET_DEFAULT, default=self.get_default_destination, related_name='destination')

Upvotes: 4

Related Questions