Django问题:ManyToMany字段返回非定义字段及多选分数求和存储
Hey there! Let's tackle your two Django issues one by one—since you're new to the framework, I'll keep things clear and actionable.
If your ManyToMany field is returning fields you didn't define, here are the most common causes and straightforward fixes:
Common Reasons & Solutions
Over-inclusive Serialization/Querying: If you're using Django REST Framework serializers or fetching related objects without limiting fields, you might be pulling in extra data from the linked model.
- Fix for Serializers: Explicitly list the fields you need instead of using
__all__:from rest_framework import serializers from .models import Asset class AssetSerializer(serializers.ModelSerializer): class Meta: model = Asset fields = ['id', 'selected_ff', 'total_score'] # Only include your desired fields - Fix for Template/View Output: When rendering data, avoid accessing unrelated attributes of linked objects. For example, if you only need the FF name, use
{{ ff.ff }}instead of dumping the entire related object.
- Fix for Serializers: Explicitly list the fields you need instead of using
Incorrect Model Setup: Double-check your ManyToMany field definition to ensure you're only linking to the intended model (your FF model). A misconfigured
related_nameor accidental model association can also pull in extra fields.
First, let's align your model structure with the data you described (this will make the calculation logic work smoothly):
from django.db import models class RType(models.Model): rtype_name = models.CharField(max_length=50, unique=True) rtype_score = models.IntegerField() def __str__(self): return self.rtype_name class FF(models.Model): ff = models.CharField(max_length=50, unique=True) ff_score = models.ForeignKey(RType, on_delete=models.CASCADE) # Links FF to its corresponding RType def __str__(self): return self.ff class Asset(models.Model): selected_ff = models.ManyToManyField(FF) total_score = models.IntegerField(default=0) # Field to store the calculated total def __str__(self): return f"Asset {self.id} - Total Score: {self.total_score}"
Now, here's how to calculate the total score when the form is submitted:
Option 1: Using a Function-Based View
If you're working with a basic function view, handle the calculation right after form validation:
from django.shortcuts import render, redirect from .forms import AssetForm def create_asset(request): if request.method == 'POST': form = AssetForm(request.POST) if form.is_valid(): # Save the Asset without committing to the database yet asset = form.save(commit=False) # Calculate total score from selected FF entries total = 0 for ff in form.cleaned_data['selected_ff']: total += ff.ff_score.rtype_score # Grab the RType score linked to each selected FF asset.total_score = total # Save the Asset and then the ManyToMany relationships asset.save() form.save_m2m() # Required when using commit=False with ManyToMany fields return redirect('asset_list') # Redirect to your asset list page else: form = AssetForm() return render(request, 'assets/create_asset.html', {'form': form})
Option 2: Using a Class-Based View (e.g., CreateView)
If you prefer class-based views, override the form_valid method to add the calculation logic:
from django.views.generic.edit import CreateView from .models import Asset from .forms import AssetForm class AssetCreateView(CreateView): model = Asset form_class = AssetForm success_url = '/assets/' # Update to your actual success URL def form_valid(self, form): # Calculate total score before saving the object self.object = form.save(commit=False) total = sum(ff.ff_score.rtype_score for ff in form.cleaned_data['selected_ff']) self.object.total_score = total self.object.save() form.save_m2m() return super().form_valid(form)
Key Notes
- If you're using a
ModelFormfor Asset, theselected_fffield will be included by default—no extra setup needed. - When updating an existing Asset, repeat the same calculation logic (override
form_validinUpdateViewor add it to your update function view) to refresh the total score.
内容的提问来源于stack exchange,提问作者mrzap

