问题是SchoolAdmin在save_related()之前调用save_model(),所以在计算分数时你的分数没有被保存。我通过覆盖save_related() 并再次调用School.save() 解决了这个问题。
我不得不猜测您的相关表格,但这里有一个完整的、可运行的代码示例。我添加了save_related() 方法。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
""" A Django web app in a single file.
To get it running, copy it into a directory named udjango:
$ pip install django
$ python udjango_web.py
Then browse to http://localhost:8000 and log in to the web site.
Tested with Django 3.0 and Python 3.8.
"""
import os
import sys
import django
from django.conf import settings
from django.conf.urls import url, include
from django.contrib.auth import get_user_model
from django.contrib import admin
from django.core.management import call_command
from django.core.wsgi import get_wsgi_application
from django.db import models
from django.db.models.base import ModelBase
from django.http import HttpResponse
WIPE_DATABASE = True
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_FILE = os.path.join(BASE_DIR, 'udjango.db')
# the current folder name will also be our app
APP_LABEL = os.path.basename(BASE_DIR)
urlpatterns = []
def main():
setup()
# Create your models here.
class County(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Weights(models.Model):
year = models.IntegerField()
weight = models.DecimalField(max_digits=5, decimal_places=2)
def __str__(self):
return str(self.year)
class School(models.Model):
name = models.CharField('school name', max_length=200)
county = models.ForeignKey(County, null=True, on_delete=models.SET_NULL)
location = models.DecimalField(blank=True, null=True, max_digits=9, decimal_places=6)
score = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2)
def __str__(self):
return '{}'.format(self.name)
def calc_score(self):
calculated_score = 0
for item in Marks.objects.filter(school=self.pk):
for weight in Weights.objects.filter(year=item.year):
new_score = item.marks * weight.weight
calculated_score = calculated_score + new_score
return calculated_score
def save(self, *args, **kwargs):
self.score = self.calc_score()
super(School, self).save(*args, **kwargs)
class Marks(models.Model):
school = models.ForeignKey(School, on_delete=models.CASCADE)
year = models.IntegerField()
marks = models.DecimalField(max_digits=5, decimal_places=2)
# Form classes
class MarksInline(admin.TabularInline):
model = Marks
@admin.register(School)
class SchoolAdmin(admin.ModelAdmin):
inlines = [
MarksInline,
]
def save_related(self, request, form, formsets, change):
super().save_related(request, form, formsets, change)
form.instance.save()
admin.site.register(County)
admin.site.register(Weights)
admin.site.register(Marks)
admin.autodiscover()
def index(request):
return HttpResponse(
"Hello, Django! <a href='admin'>Sign in</a> "
"as user 'admin', password 'admin'.")
urlpatterns.extend([
url(r'^admin/', admin.site.urls),
url(r'^$', index, name='homepage')
])
if __name__ == "__main__":
if WIPE_DATABASE or not os.path.exists(DB_FILE):
with open(DB_FILE, 'w'):
pass
call_command('makemigrations', APP_LABEL)
call_command('migrate')
get_user_model().objects.create_superuser('admin', '', 'admin')
call_command('runserver')
else:
get_wsgi_application()
def setup():
sys.path[0] = os.path.dirname(BASE_DIR)
settings.configure(
DEBUG=True,
ROOT_URLCONF=__name__,
MIDDLEWARE=[
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.locale.LocaleMiddleware',
],
INSTALLED_APPS=[
APP_LABEL,
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
],
STATIC_URL='/static/',
STATICFILES_DIRS=[
os.path.join(BASE_DIR, "static"),
],
STATIC_ROOT=os.path.join(BASE_DIR, "static_root"),
MEDIA_ROOT=os.path.join(BASE_DIR, "media"),
MEDIA_URL='/media/',
TEMPLATES=[
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "templates")],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
],
},
},
],
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': DB_FILE,
}
},
REST_FRAMEWORK={
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAdminUser',
],
}
)
django.setup()
original_new_func = ModelBase.__new__
@staticmethod
def patched_new(cls, name, bases, attrs):
if 'Meta' not in attrs:
class Meta:
app_label = APP_LABEL
attrs['Meta'] = Meta
return original_new_func(cls, name, bases, attrs)
ModelBase.__new__ = patched_new
main()