我使用 JavaScript 和 Django views.py 函数作为端点在 Django 4 Web 应用程序中实现了自动保存功能。我得到它来将表单/模型实例保存到数据库,绕过 Django 表单验证。现在的问题是它会在每个时间间隔保存新实例。
正确的行为是创建第一个实例,并在后续时间间隔中仅在自上次自动保存以来发生更改时才使用新数据更新数据库。
问题是我不知道如何存储刚刚创建的模型实例的 id,以便在每次调用自动保存 JavaScript 时我可以检查此自动保存请求是新请求还是现有请求。目前我还没有尝试过任何事情。达到可以保存未经检查的表单/模型实例的程度已经花费了我很多时间。
下面是 JavaScript 代码:
$(document).ready(function() {
var lastSavedData = $('#dormForm').serialize(); // Serialize the initial form data
function autoSave() {
var currentData = $('#dormForm').serialize(); // Serialize the current form data
// Check if the current data is different from the last saved data
if (currentData !== lastSavedData) {
$.ajax({
url: '/autosave/',
type: 'POST',
data: currentData,
success: function(response) {
if (response.status === 'success') {
console.log('Data saved');
lastSavedData = currentData; // Update lastSavedData with the new data
} else {
console.log('Error during auto save.');
}
},
error: function() {
console.log('Error during auto save.');
}
});
} else {
console.log('No changes to save.');
}
}
setInterval(autoSave, 30000); // Trigger the autoSave function every 30 seconds
});
这是 Django 4 views.py 函数:
@require_POST
def auto_save(request):
# Get the last saved instance ID from the session
last_saved_instance_id = request.session.get('last_saved_instance_id')
responses = {}
# Check if last_saved_instance_id exists and retrieve the instance
if last_saved_instance_id:
instance = get_object_or_404(LossEventPage1, pk=last_saved_instance_id)
else:
instance = LossEventPage1() # Create a new instance
# Instantiate LossEventPage1Form with the POST data and the retrieved instance
form_one = LossEventPage1Form(request.POST, request.FILES, instance=instance)
if request.method == "POST":
for field_name in form_one.fields:
field = form_one.fields[field_name]
try:
if field_name in request.POST or field_name in request.FILES:
# For files, use FILES, for other data, use POST
field_value = request.FILES.get(field_name) if isinstance(field, forms.FileField) else request.POST.get(field_name)
if field_value is not None:
# Clean and save the value for the field
field_value = field.clean(field_value)
setattr(instance, field_name, field_value)
elif field.required:
# If the field is required and not in POST, return an error response
responses['form_one'] = {
'status': 'error',
'reason': f'Missing required field: {field_name}'
}
continue # Skip saving this instance
except ValidationError as e:
# If validation fails, return an error response
responses['form_one'] = {
'status': 'error',
'reason': f'Validation error on field {field_name}: {e.messages}'
}
continue # Skip saving this instance
instance.is_draft = True # Set draft flag
instance.save() # Save the instance without calling form.save()
# You might need to handle the setting of ManyToMany fields here, after saving the instance
if 'form_one' not in responses:
responses['form_one'] = {'status': 'success'}
else:
responses['form_one'] = {'status': 'skipped', 'reason': 'No data to save for form_one'}
# Query related models and update their instances if they exist
related_models = [LossEventPage2, LossEventPage4, LossEventPage5]
for related_model in related_models:
# Query the related model's one-to-one field to find the associated instance
related_instance = related_model.objects.filter(lossEventPage1=instance).first()
# Instantiate the related model's form with the POST data and the retrieved related instance
form = related_model.form_class(request.POST, request.FILES, instance=related_instance)
if request.method == "POST":
for field_name in form.fields:
field = form.fields[field_name]
try:
if field_name in request.POST or field_name in request.FILES:
# For files, use FILES, for other data, use POST
field_value = request.FILES.get(field_name) if isinstance(field, forms.FileField) else request.POST.get(field_name)
if field_value is not None:
# Clean and save the value for the field
field_value = field.clean(field_value)
setattr(related_instance, field_name, field_value)
elif field.required:
# If the field is required and not in POST, return an error response
responses[related_model.__name__] = {
'status': 'error',
'reason': f'Missing required field: {field_name}'
}
continue # Skip saving this instance
except ValidationError as e:
# If validation fails, return an error response
responses[related_model.__name__] = {
'status': 'error',
'reason': f'Validation error on field {field_name}: {e.messages}'
}
continue # Skip saving this instance
if related_instance:
related_instance.save() # Save the related instance
if related_model.__name__ not in responses:
responses[related_model.__name__] = {'status': 'success'}
else:
responses[related_model.__name__] = {'status': 'skipped', 'reason': f'No data to save for {related_model.__name__}'}
return JsonResponse(responses)
要实现您所描述的行为,您只想在自上次自动保存以来发生更改时创建一个新实例,您可以按照以下步骤操作:
1。存储最后保存的实例的 ID: 当您最初创建实例时,您应该将创建的实例的 ID 存储在会话变量、cookie 或客户端的 JavaScript 变量中。让我们在本例中使用会话变量。
在您首次保存实例的 Django 视图中:
request.session['last_saved_instance_id'] = instance.id
2。修改 JavaScript 以检查更改: 在 JavaScript 中,您需要将表单数据与上次保存的数据进行比较,以确定是否已进行更改。如果已进行更改,则您发送自动保存请求,否则,您将跳过它。
这里有一个修改后的 JavaScript 代码,可以帮助您入门:
$(document).ready(function() {
var lastSavedData = $('#dormForm').serialize(); // Serialize the initial form data
function autoSave() {
var currentData = $('#dormForm').serialize(); // Serialize the current form data
// Check if the current data is different from the last saved data
if (currentData !== lastSavedData) {
$.ajax({
url: '/autosave/',
type: 'POST',
data: currentData,
success: function(response) {
if (response.status === 'success') {
console.log('Data saved');
lastSavedData = currentData; // Update lastSavedData with the new data
} else {
console.log('Error during auto save.');
}
},
error: function() {
console.log('Error during auto save.');
}
});
} else {
console.log('No changes to save.');
}
}
setInterval(autoSave, 30000); // Trigger the autoSave function every 30 seconds
});
3.修改 Django 视图以处理自动保存: 在 Django 视图中,您应该检查发布的数据是否与数据库中已存储的数据不同。如果有变化,则更新现有实例,否则,不执行任何操作。
您的视图应如下所示:
@require_POST
def auto_save(request):
# Get the last saved instance ID from the session
last_saved_instance_id = request.session.get('last_saved_instance_id')
responses = {}
# Check if last_saved_instance_id exists and retrieve the instance
if last_saved_instance_id:
instance = get_object_or_404(YourModel, pk=last_saved_instance_id)
else:
instance = YourModel() # Create a new instance
# ... (your existing code for populating and saving fields)
instance.save() # Save the instance without calling form.save()
# ... (your code for handling ManyToMany fields, if needed)
responses['status'] = 'success'
return JsonResponse(responses)
此方法应该可以帮助您实现所需的行为,即仅当自上次自动保存以来发生更改时才创建新实例。