I want to create a new type of field for django models that is
basically a ListOfStrings. So in your model code you would have the
following:

models.py:

   from django.db import models

   class ListOfStringsField(???):
       ???

   class myDjangoModelClass():
       myName = models.CharField(max_length=64)
       myFriends = ListOfStringsField() #

other.py:

   myclass = myDjangoModelClass()
   myclass.myName = "bob"
   myclass.myFriends = ["me", "myself", "and I"]

   myclass.save()

   id = myclass.id

   loadedmyclass = myDjangoModelClass.objects.filter(id__exact=id)

   myFriendsList = loadedclass.myFriends
   # myFriendsList is a list and should equal ["me", "myself", "and I"]


My first attempt at this looks like the following, and appears to work
as I expect:
==========================
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
==========================

However, I think it could be made a bit cleaner if it could inherit
from the proper classes inside of Django.db.models. I have looked at
the code, but my Django fu is not quite up to the task (yet). Any
pointers on making this cleaner would be much appreciated.

Sincerely,
Dudley

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to