- July 19, 2007
- models model dry common
- 4 (after 6 ratings)
Some time you want to add some common fields to a group of models, for example, in a Generalization/Specialization relationship. One could have a base model as the generalization class and specialized models with a foreign key to that base model with an unique attribute but I don't like it that way so, I just do this code to add some commons attributes to a lot of models. If you have many models that all share the same fields, this might be an option. The fields are added directly to each model, e.g. while they will be duplicated on the database level, you only have to define them once in your python code. This code is a cleaner way(I think!!!) to do it and will do the same that this one. I hope this piece of code will be useful for you.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
import types from copy import deepcopy from django.db import models class ExpanderField(object): """ This type of field can be used to include some common fields and methods in models. It take a class with those common things as parameter in the constructor and will add all fields in that class to models classes in which a field of this class type is declared. If the class containing common fields have fields of type: ForeignKey and ManyToManyField, then the related_name attribute of those fields will be renamed to a value of the form: model_name_original_value . Ej: if related_name = child_set and model name is MenuItem, it will be renamed to MenuItem_child_set. To add methods of the common class you must inherit from it. An importan thing to note here is that you must inherit first from the common class, order matters. Use case: class ContentManager(models.Manager): pass class CommonFields: pub_date = models.DateTimeField() created_by = models.ForeignKey(User, related_name = 'created_by_set') last_modified_by = models.ForeignKey(User, related_name = 'last_modified_by_set') objects = ContentManager() def save(self): #do something pass class NewsItem(CommonFields, models.Model): title = models.CharField(maxlength = 100) body = models.CharField(maxlength = 200) common = ExpanderField(CommonFields) this will create a class of this form: class NewsItem(models.Model): title = models.CharField(maxlength = 100) body = models.CharField(maxlength = 200) pub_date = models.DateTimeField() created_by = models.ForeignKey(User, related_name = 'created_by_set') last_modified_by = models.ForeignKey(User, related_name = 'last_modified_by_set') objects = ContentManager() """ def __init__(self, field_container_class): self.field_container_class = field_container_class def contribute_to_class(self, cls, name): attr_list = [attr for attr in dir(self.field_container_class) if attr not in ('__doc__', '__module__', '__class__', '__dict__')] container = self.field_container_class for attr in attr_list: clone = None attr_value = getattr(container, attr) if type(attr_value) != types.MethodType: clone = deepcopy(attr_value) if (isinstance(clone, models.ForeignKey) or isinstance(clone, models.ManyToManyField)) and \ clone.rel.related_name is not None: clone.rel.related_name = cls.__name__ + '_' + clone.rel.related_name if clone is not None: cls.add_to_class(attr, clone)