[SQLite][Django] FOREIGN KEY constraint failed

0

Czy w tej bazie danych są jakieś błędy? Przy usuwaniu rekordów otrzymuję komunikat 'FOREIGN KEY constraint failed'

from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
from django.contrib.auth.models import User
from django.db.models.signals import post_save
import datetime


class ClassCode(models.Model):
    code = models.CharField(max_length=5)


class Role(models.Model):
    name = models.CharField(max_length=100)


class Student(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    pass_changed = models.BooleanField(default=False)
    role_fk = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True, blank=True)
    class_code = models.ForeignKey(ClassCode, on_delete=models.CASCADE)


class Year(models.Model):
    year = models.IntegerField(validators=[MinValueValidator(2000), MaxValueValidator(2099)], default=datetime.datetime.now().year)
    class_code = models.ForeignKey(ClassCode, on_delete=models.CASCADE)


class MonthPayment(models.Model):
    student_fk = models.ForeignKey(Student, on_delete=models.CASCADE)
    class_code = models.ForeignKey(ClassCode, on_delete=models.CASCADE)
    month = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(9)])
    year_fk = models.ForeignKey(Year, on_delete=models.CASCADE)


class Event(models.Model):
    class_code = models.ForeignKey(ClassCode, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    date = models.DateField(blank=True, null=True)
    value = models.DecimalField(decimal_places=2, max_digits=6, validators=[MinValueValidator(0)])


class EventPayment(models.Model):
    event_fk = models.ForeignKey(Event, on_delete=models.CASCADE)
    student_fk = models.ForeignKey(Student, on_delete=models.CASCADE)
    paid = models.BooleanField(default=False)


def create_student(sender, instance, created, **kwargs): # to jest hard coded
    if created:
        Student.objects.create(id=instance.id, user=instance, class_code_id=1, role_fk_id=1)


post_save.connect(create_student, sender=User)
0

Ten błąd oznacza, że któraś tabela zawiera wiersze, których klucz obcy odwołuje się do wartości primary key innej tabeli.
Edit. https://www.sqlite.org/foreignkeys.html

0

a dokładniej usuwasz wiersze do których przez FK odwołują się inne wiersze - np. próbujesz usunąć nagłówek dokumentu do którego są pozycje

0
abrakadaber napisał(a):

a dokładniej usuwasz wiersze do których przez FK odwołują się inne wiersze - np. próbujesz usunąć nagłówek dokumentu do którego są pozycje

Ale właśnie po to ustawiam on_delete=models.CASCADE. Czy źle rozumiem ideę usuwania kaskadowego?

0

Wrzuć model i przykładowe dane na sqlfiddle.

0
yarel napisał(a):

Wrzuć model i przykładowe dane na sqlfiddle.

Miałem problemy z dodaniem na stronkę w załączniku trzymaj bazę danych i jego sql.

0

ale tam nigdzie na FK nie masz ustawionego ON DELETE (w sensie w SQLu). Wygląda na to jakby on_delete=models.CASCADE działało wyłącznie po stronie pythona a nie SQLa ale mogę się mylić

0

Wygląda na to jakby on_delete=models.CASCADE działało wyłącznie po stronie pythona a nie SQLa ale mogę się mylić

https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.CASCADE

Cascade deletes. Django emulates the behavior of the SQL constraint ON DELETE CASCADE and also deletes the object containing the ForeignKey.

Dokładnie tak działa.
@bartox; Przy jakim zapytaniu dostajesz ten błąd?

0
Delor napisał(a):

@bartox; Przy jakim zapytaniu dostajesz ten błąd?

Zawsze gdy chcę usunąć rekordy połączone kluczem obcym (powinny usuwać się kaskadowo).

0

@bartox;: chodzi o to czy usuwasz "czystym" SQLem czy przez django

0
abrakadaber napisał(a):

@bartox;: chodzi o to czy usuwasz "czystym" SQLem czy przez django

W django, panelu administratora.

0

Może to jest przyczyna:
https://docs.djangoproject.com/en/2.2/ref/contrib/admin/actions/

The “delete selected objects” action uses QuerySet.delete() for efficiency reasons, which has an important caveat: your model’s delete() method will not be called.
If you wish to override this behavior, you can override ModelAdmin.delete_queryset() or write a custom action which does deletion in your preferred manner – for example, by calling Model.delete() for each of the selected items.

0

Pewnie coś z migracjami się zwaliło. Spróbuj jeszcze usnąć normalnie przez ORMa czyli w view pobierz obiekt i go usuń delete()( tak tak głupota ale może pomóc)

0
  1. W tym Twoim modelu bazodanowym (nie django) nie masz zdefiniowanych FK jako ON DELETE CASCADE, tylko coś w stylu:
FOREIGN KEY("event_fk_id") REFERENCES "klasowe_event"("id") DEFERRABLE INITIALLY DEFERRED,
FOREIGN KEY("student_fk_id") REFERENCES "klasowe_student"("id") DEFERRABLE INITIALLY DEFERRED
  1. W SQLLIte jest taki wynalazek jak PRAGMAS i jest też przełącznik (domyślnie wyłączony) dla kluczy obcych. Internety mówią, że dla DELETE CASCADE potrzebujesz PRAGMA foreign_keys=ON.
0
yarel napisał(a):
  1. W tym Twoim modelu bazodanowym (nie django) nie masz zdefiniowanych FK jako ON DELETE CASCADE, tylko coś w stylu:
FOREIGN KEY("event_fk_id") REFERENCES "klasowe_event"("id") DEFERRABLE INITIALLY DEFERRED,
FOREIGN KEY("student_fk_id") REFERENCES "klasowe_student"("id") DEFERRABLE INITIALLY DEFERRED

I raczej nie będzie, bo z tego co zrozumiałem to django triggeruje usuwanie kaskadowe.

  1. W SQLLIte jest taki wynalazek jak PRAGMAS i jest też przełącznik (domyślnie wyłączony) dla kluczy obcych. Internety mówią, że dla DELETE CASCADE potrzebujesz PRAGMA foreign_keys=ON.

Też to widziałem, ale to chyba w czystym sqllite. Jak na moje django powinien to robić za mnie.
Jutro spróbuję usunąć db, wykonać migracje, ew. virtualenv również od nowa.

0

no przecież @Delor wstawił Ci cytat z helpa czemu to nie działa.

0

Trzeba zobaczyć migracje, czy te modele były zrobione raz i migracje czy coś edytowałeś i zrobiłeś kilka migracji dla tych modeli?

0

Zrobiłem nowy projekt. Wrzuciłem Twoje modele.
makemigrate - Ok
migrate - Ok
createsuperuser - constraint failed (brak rekordów aby stworzyć Student w create_student()) ale bez transakcji więc User dodany i można użyć panelu
Po dodaniu odpowiednich rekordów: SOA#1
Działa dodawanie, edycja, usuwanie.
Wykasuj migracje i plik bazy danych (domyślnie db.sqlite3) i zacznij od początku.

1 użytkowników online, w tym zalogowanych: 0, gości: 1