class DynForm(forms.BaseForm):
    """
        Given defined fields exclude,include,model, and widgets this class will attempt to build a form from a model definition
        like form_for_model/instance.  The only required field is model.  exclude,include, and widgets can be left off in which
        case all fields except the primary key field will be used with default widgets.
        
        exclude =[List of model field names] Can be empty or undefined which will exclude only the primary key field
        include =[List of model field names] Can be empty or undefined which will make it use all fields in model
        widgets = {'field': (widgetmodel,{widget args}),}
        formfields = {'field': (formfieldmodel,{formfield args}),}  the widgets dict above  will override any widgets specified 
            here.
        
        If you specify an 'include' list it's pointless to specify and 'exclude' list because only the fields in include will be used.
        'exclude' is really only useful if you want almost all the model fields except for one or two, which you'd put in the list
        and leave include empty or undefined to get all the other fields automatically.
        
        This not really a normal form, so some things may not work the same as you might expect.
        
        To emmulate form_for_model you'd basically do the bare minimum
        
            class MyForm(DynForm):
                model = MyModel
        
        Unbound form:
            form = AgentEditForm()
        Bound to a pk for the model defined, and will use that data to populate as initial if it exists.  
            form =  AgentEditForm(None,pk=5) # Agent.objects.get(pk=5)
        Bound to a pk, and processing POST
            form = AgentEditForm(request.POST,pk=5)  
            
        optional keyword arguments
            pk  -   primary key. Will fallback to None if pk not valid
            widget_kwargs  - Dictionary field keys, and a dict with keyword args
                for the fields widget used instead of those in form definition (models_def) 

        form.save()  -  
                If no primary key (pk) was given at form creation, or the pk was invalud a new object will 
                be created and the object will be returned.  Any keyword arguments passed to save will be 
                used to instantiate a new new instance for the model, but will be overridden by form data if 
                present.  This is to allow you to define values for required fields you excluded
                in the form definition. 
                
        ------------------------------------------------------------------------------------------------------------------------------------------------------
        Example form:
            class AgentReminderForm(DynForm):
                model= AgentReminder
                include_fields=['who','what','when','priority','notice','date']
                exclude_fields=[]
                widgets= {  'what': (forms.Textarea,{'attrs':{'rows':'5','cols':'10'},}),
                                    'notice': (forms.Select,{'choices': [('15','15 Minutes'),('60','1 Hour')]}), 
                    }
                formfields ={ 'when': (forms.DateTimeField,{'input_formats': ["%b-%d-%Y %I:%M:%S %p"] }) 
                    }

        ------------------------------------------------------------------------------------------------------------------------------------------------------
        In View:
            def myview(request,id=None)
            if request.POST:
                form =  AgentReminderForm(request.POST,pk=id)
                if form.is_valid():
                    form.save(date=datetime.now())
            else:
                form=AgentReminderForm(pk=id)
            ...
    """
    def __init__(self, *args, **kwargs):
        try:
            getattr(self,'include')
        except:
            self.include = []
        try:
            getattr(self,'exclude')
        except:
            self.exclude = []
        try:
            getattr(self,'widgets')
        except:
            self.widgets = {}
        try:
            getattr(self,'formfields')
        except:
            self.formfields = {}
        newkwargs = kwargs
        self.base_fields = {} # Since we are bypassing Form and using BaseForm
        if 'widget_kwargs' in kwargs:
            self.widget_kwargs = newkwargs.pop('widget_kwargs')
        else:
            self.widget_kwargs = {}
        self.primary_key=None
        if 'pk' in kwargs:
            self.primary_key = newkwargs.pop('pk')
            try:
                mi = self.model.objects.get(pk=self.primary_key)
            except:
                self.primary_key = None
        if self.primary_key:
            newinitial = mi.__dict__
            if 'initial' in newkwargs:
                newinitial.update(newkwargs['initial'])
            newkwargs['initial'] = newinitial
        super(DynForm,self).__init__(*args,**newkwargs)
        mm = self.model._meta   # grab the model info
        include = []
        if self.include:
            for field in mm.fields + mm.many_to_many:
                if field.attname in self.include:
                    include.append(field)
        else:
            include = mm.fields + mm.many_to_many
        self.exclude.append(mm.pk.attname)
        for f in include:
            if (f.attname not in self.exclude) and (f is not mm.pk.attname) :
                if f.attname in self.formfields:
                    formfield = self.formfields[f.attname][0]
                    ffargs = self.formfields[f.attname][1]
                else:
                    formfield = f.formfield
                    ffargs = {}
                # Handle Widgets    
                if f.attname in self.widget_kwargs: #use what was given at form instantiation
                    ffargs['widget'] =self.widgets[f.attname][0](**self.widget_kwargs[f.attname][1])
                elif f.attname in self.widgets: # use what was given at form definition
                    ffargs['widget'] =self.widgets[f.attname][0](**self.widgets[f.attname][1] )
                self.fields[f.attname] = formfield(**ffargs)
        self.base_fields=self.fields # don't actually need this, but just in case someone tries to treat as a normal form

    def save(self, **kwargs):
        if not self.is_valid():
            return None
        rel_wait = [] # start with no many to many relations to worry about
        q_wait = [] # start with no fields to queue until after initial save
        if self.primary_key is None: # treat as new
            pm = self.model(**kwargs)
            # since this is new, put any waiting fields in the rel_wait list
            for mf in pm.__class__._meta.many_to_many:
                rel_wait.append(mf.attname)
        else:
            pm = self.model.objects.get(pk=self.primary_key)
        for f in self.fields: 
            if f not in rel_wait:
                setattr(pm,f,self.clean_data[f])
            else:
                q_wait.append(f)
        pm.save() # Must save here, so relations work
        if len(q_wait) > 0:  # something is queued, and can now be added since the insert is done and pm has a pk     
            for f in q_wait:   # now that it's inserted we can take care of the waiting relations
                setattr(pm,f,self.clean_data[f])
            pm.save()
        return pm