Je souhaite créer un nouveau type de champ pour les modèles Django qui est fondamentalement une liste de lecture. Donc, dans votre code modèle, vous auriez les suivants:
modèles.py: strong> p> autre.py: strong > p> Comment allez-vous écrire ce type de champ, avec les stipulations suivantes? p> regarder dans le code Django, on dirait que je voudrais faire quelque chose de similaire à ce que fait la tâche de l'entreprise étrangère, mais la documentation est clairsemée. P> Ceci conduit aux questions suivantes: p> Ceci est proviennent de cette question . p> p>
5 Réponses :
Il existe une très bonne documentation sur la création de champs personnalisés ici A >. Cependant, je pense que vous pensez cela. On dirait que vous voulez réellement une clé étrangère standard, mais avec la possibilité supplémentaire de récupérer tous les éléments en tant que liste unique. Donc, la tâche la plus simple serait de simplement utiliser une méthode de l'entreprise étrangère et de définir une méthode appelant maintenant get_myfield_as_list code> sur le modèle: p>
get_my_friends_as_list ( ) code> sur une instance de MyModel vous retournera une liste des chaînes, selon les besoins. p> p>
J'aurais pensé que la classe fourrtuelle appartient à la classe d'amis. Est-ce que je manque quelque chose? Et oui, je suis probablement en train de penser cela, mais si je peux créer le champ, je veux, je pense que ce serait généralement utile.
Je pense que FK est le moyen d'aller ici aussi. +1 pour ajouter la méthode pour récupérer des amis sous forme de liste.
Je pense aussi que vous allez à ce sujet le mauvais sens. Essayer de faire un champ Django Créer une table de base de données auxiliaire est presque certainement la mauvaise approche. Il serait très difficile de faire et confondrait probablement des développeurs tiers si vous essayez de rendre votre solution généralement utile.
Si vous essayez de stocker une blob de données dénormalisée dans une seule colonne, je prendrais Une approche similaire à celle que vous avez liée, sérialisant la structure de données Python et la stockant dans un champ de texte. Si vous souhaitez que les outils autres que Django puissent fonctionner sur les données, vous pouvez Serialize à JSON (ou un autre format qui dispose d'un support de langue large): P>
from django.db import models from django.utils import simplejson class JSONDataField(models.TextField): __metaclass__ = models.SubfieldBase def to_python(self, value): if value is None: return None if not isinstance(value, basestring): return value return simplejson.loads(value) def get_db_prep_save(self, value): if value is None: return None return simplejson.dumps(value)
Je viens de recevoir une chance de regarder le lien que vous avez posté. Je pense qu'il est plus proche de ce que j'essaie de faire de la mise en œuvre de la mise en œuvre que ce que j'ai actuellement. Merci!
+1 Pour seulement utiliser cette approche si sa dénormalisation! Sinon, normaliser!
Notez que get_db_prep_save prend maintenant 4 arguments (à partir de Django 1.5)
Merci pour tous ceux qui ont répondu. Même si je n'ai pas utilisé votre réponse directement, les exemples et les liens me gênais dans la bonne direction.
Je ne suis pas sûr de la production, mais cela semble fonctionner dans tous mes tests jusqu'à présent. P>
class ListValueDescriptor(object): def __init__(self, lvd_parent, lvd_model_name, lvd_value_type, lvd_unique, **kwargs): """ This descriptor object acts like a django field, but it will accept a list of values, instead a single value. For example: # define our model class Person(models.Model): name = models.CharField(max_length=120) friends = ListValueDescriptor("Person", "Friend", "CharField", True, max_length=120) # Later in the code we can do this p = Person("John") p.save() # we have to have an id p.friends = ["Jerry", "Jimmy", "Jamail"] ... p = Person.objects.get(name="John") friends = p.friends # and now friends is a list. lvd_parent - The name of our parent class lvd_model_name - The name of our new model lvd_value_type - The value type of the value in our new model This has to be the name of one of the valid django model field types such as 'CharField', 'FloatField', or a valid custom field name. lvd_unique - Set this to true if you want the values in the list to be unique in the table they are stored in. For example if you are storing a list of strings and the strings are always "foo", "bar", and "baz", your data table would only have those three strings listed in it in the database. kwargs - These are passed to the value field. """ self.related_set_name = lvd_model_name.lower() + "_set" self.model_name = lvd_model_name self.parent = lvd_parent self.unique = lvd_unique # only set this to true if they have not already set it. # this helps speed up the searchs when unique is true. kwargs['db_index'] = kwargs.get('db_index', True) filter = ["lvd_parent", "lvd_model_name", "lvd_value_type", "lvd_unique"] evalStr = """class %s (models.Model):\n""" % (self.model_name) evalStr += """ value = models.%s(""" % (lvd_value_type) evalStr += self._params_from_kwargs(filter, **kwargs) evalStr += ")\n" if self.unique: evalStr += """ parent = models.ManyToManyField('%s')\n""" % (self.parent) else: evalStr += """ parent = models.ForeignKey('%s')\n""" % (self.parent) evalStr += "\n" evalStr += """self.innerClass = %s\n""" % (self.model_name) print evalStr exec (evalStr) # build the inner class def __get__(self, instance, owner): value_set = instance.__getattribute__(self.related_set_name) l = [] for x in value_set.all(): l.append(x.value) return l def __set__(self, instance, values): value_set = instance.__getattribute__(self.related_set_name) for x in values: value_set.add(self._get_or_create_value(x)) def __delete__(self, instance): pass # I should probably try and do something here. def _get_or_create_value(self, x): if self.unique: # Try and find an existing value try: return self.innerClass.objects.get(value=x) except django.core.exceptions.ObjectDoesNotExist: pass v = self.innerClass(value=x) v.save() # we have to save to create the id. return v def _params_from_kwargs(self, filter, **kwargs): """Given a dictionary of arguments, build a string which represents it as a parameter list, and filter out any keywords in filter.""" params = "" for key in kwargs: if key not in filter: value = kwargs[key] params += "%s=%s, " % (key, value.__repr__()) return params[:-2] # chop off the last ', ' class Person(models.Model): name = models.CharField(max_length=120) friends = ListValueDescriptor("Person", "Friend", "CharField", True, max_length=120)
J'ai remarqué avec cette classe, que vous devez enregistrer avant d'ajouter, puisque l'identifiant n'existe pas tant que vous économisez. Je pense que cela pourrait être réparé / corrigé si cela a hérité du champ associé et du champ, mais j'essaie toujours d'envelopper ma tête autour de ce code.
Après plus d'expérimentations, cela s'avère travailler, mais est extrêmement fragile, surtout en ce qui concerne les espaces de noms, il doit vivre dans des modèles.py. Je continuerai à travailler dessus et j'espère développer une version plus propre.
Qu'est-ce que vous avez décrit me semble vraiment similaire aux tags.
Alors, pourquoi ne pas utiliser django marquant ?
Cela fonctionne comme un charme, vous pouvez l'installer indépendamment de votre application et son API est assez facile à utiliser. P>
De plus, si cela ne fonctionne pas comme le veut, il est facile de regarder comment cela est fait là-bas et la modifier à ses besoins.
Joli! Je vais devoir examiner cela plus loin.
C'est certainement possible, bien que je ne connais pas les détails. Je dis à lire leur liste de diffusion et à regarder à travers les documents, mais vous devrez finalement avoir à creuser à travers la source de Django.
Je suis en train de creuser à travers la source maintenant. Si je parviens à proposer une chose qui fonctionne, je vais essayer de le poster ici.
Posté ma tentative ci-dessous, qui semble fonctionner.
Donc, ma tentative ci-dessous fonctionne, mais est extrêmement fragile et sujette d'erreur. :(