Reputation: 620
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
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