DB / performance: mise en page d'un modèle django faisant rarement référence à son parent plus d'une fois
-
10-07-2019 - |
Question
J'ai une application qui présente les villes simplifiées fictives.
Veuillez considérer les modèles Django suivants:
class City(models.Model):
name = models.CharField(...)
...
TYPEGROUP_CHOICES = (
(1, 'basic'),
(2, 'extra'),
)
class BldgType(models.Model):
name = models.CharField(...)
group = models.IntegerField(choices=TYPEGROUP_CHOICES)
class Building(models.Model):
created_at = models.DateTimeField(...)
city = models.ForeignKey(City)
type = models.ForeignKey(BldgType)
other_criterion = models.ForeignKey(...)
class Meta:
get_latest_by = 'created_at'
Explications relatives au choix de cette configuration:
(1) Chaque ville possède certains bâtiments de type "basique" saisissez exactement une fois par ville (exemples: mairie, caserne de pompiers, commissariat de police, hôpital, école) et éventuellement des dizaines de bâtiments de "extra". type, tels que les clubs de danse.
(2) Dans certaines vues, tous les bâtiments (quelle que soit la ville, etc.) doivent être filtrés en fonction de critères différents, par exemple, other_criterion
.
Problème / préoccupation:
Dans une vue city_detail
, il me faudrait parcourir en boucle tous les bâtiments de " extra " tapez, ce qui est correct et normal.
Mais je ne suis pas sûr de savoir comment récupérer efficacement le "hôpital" de la ville. bâtiment, qui est de "base" De toute façon, je dois le faire pour chaque ville car il existe exactement un hôpital de ce type dans chaque ville (cela est garanti au moment de la création de la ville).
Il y aura au plus une douzaine de " bases " types de bâtiments, dont environ la moitié sera présentée tout le temps.
Je suis enclin à écrire des méthodes pratiques sur le modèle City, et je suis confronté à trois options:
(A1) Via , essayez
et index: .filter (...) [0]
(A2) Via essayer
et .get (...)
(A3) Via , essayez
et .filter (...). latest ()
Mais aucun de ceux-ci ne semble élégant.
Ou bien l’une de ces trois options peut-elle être combinée à une sorte de mise en cache, comme dans la méthode get_profile ()
de Django sur le modèle Utilisateur
? Malheureusement, je n'ai pas encore d'expérience en cache.
Est-ce que c'est fou d'utiliser l'option suivante?
(B) FK spécifiques dans le modèle de ville, un pour chacun des types de base les plus importants
Question:
Quelle option est la plus logique?
Ou bien le schéma est-il généralement défectueux pour ce genre de scénario?
Que proposez-vous en particulier en ce qui concerne les performances de base de données? Ai-je besoin d'une approche complètement différente?
S'il vous plaît aviser! :)
Merci d'avance!
La solution
Si une ville ne peut pas avoir plus d'un hôtel de ville, caserne de pompiers, poste de police, hôpital, école, etc., je pense que le moyen le plus simple de l'appliquer est de déclarer chacun d'eux comme un champ du modèle:
class City(models.Model):
name = models.CharField(...)
city_hall = models.ForeignKey(Building)
fire_station = models.ForeignKey(Building)
# ... et cetera
Si vous trouvez cela aussi "désordonné" dans votre modèle de ville, vous pouvez envisager de créer un modèle CityBuildings
intermédiaire:
class CityBuildings(models.Model):
city_hall = models.ForeignKey(Building)
fire_station = models.ForeignKey(Building)
# ... et cetera
class City(models.Model):
name = models.CharField(...)
buildings = models.OneToOneField(CityBuildings)
Vous faites ensuite référence aux bâtiments comme, par exemple, city.buildings.fire_station
Ce ne sont que des suggestions ... Je ne sais pas si l'une ou l'autre solution est plus "correcte"
Autres conseils
Pour tous ceux qui sont intéressés: stupide, j'ai découvert l’existence de la technique de mémorisation, c’est pourquoi je vais utiliser une forme de celle appliquée à (A2), englobée dans autant de méthodes pratiques que sur le modèle City "basique". types de bâtiments.
Cela est au moins un peu moins compliqué que d'avoir des FK dans deux directions et permet au code d'être plus clair sur la séparation des intérêts (modélisation d'un côté, performances de l'autre).
Sur le vif, j’ai élaboré deux projets à étudier en matière d’apprentissage et éventuellement de prêt ou d’application directe:
- django-memoize
- github.com/husio/django-easycache /
Peut-être que quelqu'un trouvera cela utile également.