[python] Champs de modèles dynamiques Django



Answers

J'ai travaillé sur pousser l'idée django-dynamo plus loin. Le projet n'est toujours pas documenté mais vous pouvez lire le code sur https://github.com/charettes/django-mutant .

En fait, les champs FK et M2M (voir contrib.related) fonctionnent également et il est même possible de définir un wrapper pour vos propres champs personnalisés.

Il existe également une prise en charge des options de modèle, telles que le modèle unique_together et la commande, ainsi que les bases du modèle, ce qui vous permet de sous-classer le modèle proxy, le résumé ou les mixins.

Je travaille actuellement sur un mécanisme de verrouillage non en mémoire pour m'assurer que les définitions de modèles peuvent être partagées à travers plusieurs instances en cours d'exécution de django tout en les empêchant d'utiliser une définition obsolète.

Le projet est encore très alpha mais c'est une technologie de base pour un de mes projets, je vais donc devoir le mettre en production. Le grand plan supporte également django-nonrel afin que nous puissions tirer parti du pilote mongodb.

Question

Je travaille sur une application multi-locataire dans laquelle certains utilisateurs peuvent définir leurs propres champs de données (via l'admin) pour collecter des données supplémentaires dans des formulaires et générer des rapports sur les données. Ce dernier bit rend JSONField pas une bonne option, donc j'ai la solution suivante:

class CustomDataField(models.Model):
    """
    Abstract specification for arbitrary data fields.
    Not used for holding data itself, but metadata about the fields.
    """
    site = models.ForeignKey(Site, default=settings.SITE_ID)
    name = models.CharField(max_length=64)

    class Meta:
        abstract = True

class CustomDataValue(models.Model):
    """
    Abstract specification for arbitrary data.
    """
    value = models.CharField(max_length=1024)

    class Meta:
        abstract = True

Notez comment CustomDataField a un ForeignKey sur Site - chaque Site aura un ensemble différent de champs de données personnalisés, mais utilisera la même base de données. Ensuite, les différents champs de données concrets peuvent être définis comme:

class UserCustomDataField(CustomDataField):
    pass

class UserCustomDataValue(CustomDataValue):
    custom_field = models.ForeignKey(UserCustomDataField)
    user = models.ForeignKey(User, related_name='custom_data')

    class Meta:
        unique_together=(('user','custom_field'),)

Cela conduit à l'utilisation suivante:

custom_field = UserCustomDataField.objects.create(name='zodiac', site=my_site) #probably created in the admin
user = User.objects.create(username='foo')
user_sign = UserCustomDataValue(custom_field=custom_field, user=user, data='Libra')
user.custom_data.add(user_sign) #actually, what does this even do?

Mais cela semble très maladroit, en particulier avec la nécessité de créer manuellement les données associées et de les associer au modèle concret. Est-ce qu'il y a une meilleure approche?

Options qui ont été rejetées de manière préemptive:

  • SQL personnalisé pour modifier les tables à la volée. En partie parce que cela ne sera pas à l'échelle et en partie parce que c'est trop un hack.
  • Des solutions sans schéma comme NoSQL. Je n'ai rien contre eux, mais ils ne vont toujours pas bien. En fin de compte, ces données sont saisies et il est possible d'utiliser une application de reporting tierce.
  • JSONField, comme indiqué ci-dessus, car il ne fonctionnera pas bien avec les requêtes.



Links