Django模型:仅数字不同的属性命名与赋值问题
Hey there! Let's tackle this common Django modeling problem where you've got fields like m_energy_1, m_energy_2, etc., with only sequential number suffixes differing. This pattern usually signals we can structure things more cleanly and maintainably—here are your best options, tailored to different use cases:
Option 1: Use a JSONField (or JSONBField for PostgreSQL)
If the number of energy values might grow over time, or you don't need to query individual values frequently, storing them in a JSON array is a simple, flexible fix. This eliminates the need to add new model fields every time you need another energy reading.
Model Adjustment:
from django.db import models class UserPhraseDatum(models.Model): result_from = models.ForeignKey(Results, related_name="data") phrase = models.ForeignKey(Sound) score = models.DecimalField(max_digits=5, decimal_places=4) snr = models.PositiveSmallIntegerField() m_energies = models.JSONField(default=list) # Replaces all m_energy_* fields
Assignment Example:
# Assign multiple energy values in one go datum = UserPhraseDatum.objects.create( result_from=my_result, phrase=my_sound, score=0.8765, snr=42, m_energies=[150, 220, 180, 250, 190] ) # Add a new energy value later datum.m_energies.append(210) datum.save()
You can still query against the JSON array using Django's built-in JSON lookups (like __contains, __icontains, or array index lookups) if needed.
Option 2: Create a Related One-to-Many Model
If you need to filter, sort, or perform complex queries on individual energy values (or if each reading might need additional metadata later), a separate related model is the way to go. This is the most scalable and database-friendly approach for structured, queryable data.
Related Model Setup:
class EnergyReading(models.Model): user_phrase_datum = models.ForeignKey( UserPhraseDatum, related_name="energy_readings", on_delete=models.CASCADE ) position = models.PositiveSmallIntegerField() # Tracks the sequence (1, 2, 3...) value = models.PositiveSmallIntegerField() # Updated UserPhraseDatum (remove all m_energy_* fields) class UserPhraseDatum(models.Model): result_from = models.ForeignKey(Results, related_name="data") phrase = models.ForeignKey(Sound) score = models.DecimalField(max_digits=5, decimal_places=4) snr = models.PositiveSmallIntegerField()
Assignment Example:
# Create the parent datum first datum = UserPhraseDatum.objects.create( result_from=my_result, phrase=my_sound, score=0.8765, snr=42 ) # Bulk create energy readings for efficiency EnergyReading.objects.bulk_create([ EnergyReading(user_phrase_datum=datum, position=i+1, value=val) for i, val in enumerate([150, 220, 180, 250, 190]) ])
This lets you easily query things like "all UserPhraseDatum where the 3rd energy reading is over 200" with UserPhraseDatum.objects.filter(energy_readings__position=3, energy_readings__value__gt=200).
Option 3: Rename Fields to Have Semantic Meaning (If Count Is Fixed)
If you know the number of energy values will never change (e.g., exactly 5), replace the numeric suffixes with descriptive names that explain what each value represents. This makes your model self-documenting and avoids confusion about what m_energy_3 actually means.
Model Adjustment:
class UserPhraseDatum(models.Model): result_from = models.ForeignKey(Results, related_name="data") phrase = models.ForeignKey(Sound) score = models.DecimalField(max_digits=5, decimal_places=4) snr = models.PositiveSmallIntegerField() # Replace numeric suffixes with meaningful names m_energy_band_1 = models.PositiveSmallIntegerField() m_energy_band_2 = models.PositiveSmallIntegerField() m_energy_band_3 = models.PositiveSmallIntegerField() m_energy_band_4 = models.PositiveSmallIntegerField() m_energy_band_5 = models.PositiveSmallIntegerField()
Assignment Example:
datum = UserPhraseDatum.objects.create( result_from=my_result, phrase=my_sound, score=0.8765, snr=42, m_energy_band_1=150, m_energy_band_2=220, m_energy_band_3=180, m_energy_band_4=250, m_energy_band_5=190 )
How to Choose?
- Go with JSONField if you need flexibility and don't need heavy querying on individual values.
- Use a related model if you need to query, filter, or extend individual readings.
- Stick with semantic field names only if the number of values is fixed and you can clearly name each one.
内容的提问来源于stack exchange,提问作者AmagicalFishy




