How do I store multiple copies of the same field in Django?
I'm storing OLAC metadata which describes linguistic resources. Many of the elem开发者_运维知识库ents of the metadata are repeatable -- for example, a resource can have two languages, three authors and four dates associated with it.
Is there any way of storing this in one model? It seems like overkill to define a model for each repeatable metadata element -- especially since the models will only have one field: it's value.
It sounds like the best way would be via many to many relationships, like this:
class author(models.Model):
# fields?
class language(models.Model):
iso_lang_code = models.CharField() # probably need some constraints here
class resource(models.Model):
name = models.CharField()
authors = models.ManyToManyField(Author)
languages = models.ManyToManyField(Language)
Then when it comes to create a resource, you simply do:
r = resource(name="")
a1 = author(name="ninefingers")
a2 = author(name="jon skeet", type="god")
r.authors.add(a1)
r.authors.add(a2)
english = languages.objects.get(iso_lang_code="en-GB")
r.add(english)
r.save()
And you can also do some really fancy stuff like:
english = languages.objects.get(iso_lang_code="en-GB")
resourcesinenglish = english.resource_set.all()
for r in resourcesinenglish:
# do something on r.
So using the ORM this way is really powerful. Yes, you basically end up with an ISO list of languages in an SQL table, but is that a problem? If so, you could always replace it with a
string and use objects.filter(language='en-GB')
which (roughly) translates to the sql of
WHERE language='en-GB'
. Of course, you are then limited to one language only.
Another approach might be to write all the languages as ISO codes modified by a splitter, say ;
then do
r = resource.objects.get(id=701)
langs = r.languages.split(';')
for l in language:
print l
Of course, maintaining said list becomes more difficult that way. I think the ORM is easier by far.
As for more complex types like Authors
the ORM is by far the easiest way to go.
Note that if you're concerned about the number of database requests this is creating, you can always use select_near
. This does exactly what it sounds like - follows all foreign keys, so your database gets hit one massively and then is left alone as the objects are then in memory (cached).
You could also choose to do a 'tag' element. This could have two fields, a type and a value. Something like this:
class TagType(models.Model):
name = models.CharField(max_length=50)
class Tag(models.Model):
type = models.ManyToManyField(TagType)
value = models.CharField(max_length=200)
class Resource(models.Model):
name = models.CharField(max_length=50)
tag = models.ManyToManyField(Tag)
You could chose to just have the tag type be a charfield but I prefer to have it be a separate model because you can use the admin interface to enter a series of types and then select them from a drop down when you wish to add a new tag.
EDIT: I should note that the above solution is better because it will make it easier to deal with the data later. If you're ever going to do more than simply enter this information I advise defining the full models.
精彩评论