Search code examples
pythondjangomixins

Get only the non-inherited fields for a Django mixin


I would like to get all the non-inherited fields defined in a model. That is, I want the fields defined only in the "submodel", not the base ('abstract') model. (Ultimate purpose: create a ModelForm that only includes the fields defined in the "submodel" - dynamically, without having to write out the specific fields).

Typically calling vars(Subclass).keys() will give you only the attributes of Subclass while dir(Subclass) will give you the attributes of both SubClass and its inherited class. I'm trying to use the same paradigm to get only the fields defined in SubModel:

class Submodel(models.AbstractModel):
    field1=...
    field2=...

class AbstractModel(models.Model):
    fields...
    class Meta:
        abstract=True

But when I call vars(Submodel).keys() I get the following (pprinted):

[u'__module__',
 '_meta',
 'MultipleObjectsReturned',
 'get_next_by_submission_datetime',
 'get_next_by_some_date_and_time',
 '_base_manager',
 'objects',
 '_default_manager',
 'get_previous_by_submission_datetime',
 'the_foreignkey_field_in_abstractmodel',
 'get_previous_by_some_date_and_time',
 'DoesNotExist',
 '__doc__',
 '__unicode__']

I'm not sure why this is returning stuff that is not defined in the Submodel (that seems inconsistent with the usual behavior of vars() ). And now that I think some more about it, as soon as I define methods on the Submodel, it will return those, which I don't want for constructing a ModelForm.

I have also tried Submodel._meta.fields and Submodel._meta.many_to_many but those return all of the fields of both AbstractModel and Submodel.

So the main question is: is there a good way to get only the fields defined in the submodel?

And the minor question is: why is vars() doing that?

EDIT:

In the form definition, what I want to do is:

class ExampleinheritForm(ModelForm):
    class Meta:
        model = Submodel
        fields = some_function_to_return_only_Submodel_fields()

Solution

  • Well here's what I ended up doing - works great for me so far.

    @classmethod
    def  get_userdefined_formfields(cls): 
        """Takes all the model fields on a concrete model, 
        and subtracts out the ones in the parent (abstract) model."""
        allfields = cls._meta.fields + cls._meta.many_to_many
        #this assumes we only inherit from one abstract model
        #could be modified if that were not the case
        parentfields = AbstractModel._meta.fields + AbstractModel._meta.many_to_many
        #filter out parent fields
        childfields = [f for f in allfields if f not in parentfields]
        #filter out auto fields and fields without help text, return names
        return childfields