Mohamed Samir
Mohamed Samir

Reputation: 399

explaining custom model fields mechanism

this not the first time to have the feeling stuck in a challenging new thing. but it may be the first to be not able to have an external blogs explaining the subject except the docs . so i hope to find some one explain the fundamentals of creating a custom django model field. here is an example if you want to know what i am facing

class OrderField(models.PositiveIntegerField):
def __init__(self, for_fields=None, *args, **kwargs):
    self.for_fields = for_fields
    super(OrderField, self).__init__(*args, **kwargs)

def pre_save(self, model_instance, add):
    if getattr(model_instance, self.attname) is None:
        # no current value
        try:
            qs = self.model.objects.all()
            if self.for_fields:
                # filter by objects with the same field values
                # for the fields in "for_fields"
                query = {field: getattr(model_instance, field)\
                for field in self.for_fields}
                qs = qs.filter(**query)
            # get the order of the last item
            last_item = qs.latest(self.attname)
            value = last_item.order + 1
        except ObjectDoesNotExist:
            value = 0
        setattr(model_instance, self.attname, value)
        return value
    else:
        return super(OrderField,
                     self).pre_save(model_instance, add)

i have read some of the docs, but feel free to explain it as it's for any one with no prior experience so everyone will find it helpful

Upvotes: 0

Views: 177

Answers (2)

Mohamed Samir
Mohamed Samir

Reputation: 399

class OrderField(PositiveIntegerField):
    def __init__(self, for_fields=None, *args, **kwargs):
        self.for_fields = for_fields
        super().__init__(*args, **kwargs)

    def pre_save(self, model_instance, add):
#if the field isn't existed yet in the object 
#(as we could have saved the object before and resaving it for some reason like updating )
        if getattr(model_instance, self.attname) is None: #self.attname is the name of the field in the model

            try:
                qs = self.model.objects.all()
                if self.for_fields:
                    # get objects that has the same fields(with same vlaues) in for_fields 
                    #it's like so 
                    #for_fields = 'course, module, title'
                    # the query will be the value of these fields on the instance which we work on now(and have this field(orderfield ) and will be saved)
                    # course = 1 we assume it's one in this instanse 
                    # module = 3 and so on for the title
                    query = {field: getattr(model_instance, field) for field in self.for_fields}                                                                          
                    qs = qs.filter(**query)                                
                last_item = qs.latest(self.attname)
                value = last_item.order + 1
            except ObjectDoesNotExist:
                value = 0
            setattr(model_instance, self.attname, value)
            return value
        else:
            return super(OrderField, self).pre_save(model_instance, add)

Upvotes: 2

Sina Khelil
Sina Khelil

Reputation: 1991

From the look of it, it is inheriting the functionality of models.PositiveIntegerField and modifying into a field with an ever increasing number - therefore the pre-save that looks for the latest value and increments it by 1

Upvotes: 0

Related Questions