问题
I have a model with a get_form method.
# models.py
from model_utils.managers import InheritanceManager
from breathingactivities.forms import ParentRecordForm, ChildRecordForm
class ParentRecord(models.Model):
....
objects = InheritanceManager()
def get_fields(self, exclude=('user')):
fields = self._meta.fields
return [(f.verbose_name, f.value_to_string(self)) for f in fields if not exclude.__contains__(f.name)]
@classmethod
def get_form(self, *args, **kwargs):
return ParentRecordForm
class ChildRecord(ParentRecord):
....
duration = DurationField(
_('Duration'),
help_text=_('placeholder'))
@classmethod
def get_form(self, *args, **kwargs):
return ChildRecordForm
I have a view that uses this get_form method to determine to correct form for a given object.
# views.py
class ParentRecordUpdateView(UpdateView):
model = ParentRecord
form_class = ParentRecordForm
template_name = 'parentrecords/create.html'
def get_object(self, **kwargs):
return ParentRecord.objects.get_subclass(slug=self.kwargs['slug'])
def get_form_class(self, *args, **kwargs):
form_class = self.model.objects.get_subclass(slug=self.kwargs['slug']).get_form()
return form_class
def get_form_kwargs(self):
kwargs = super(ParentRecordUpdateView, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
I am using InheritanceManager from django-model-utils so I get a clean API to subclasses when I query a parent class - that is the get_subclass() stuff, and this is why my view works with ParentRecord.
All this works good. I see via console that indeed form_class is the form class I'd expect, for example, ChildRecordForm when the instance is of ChildRecord.
In my forms.py, I can't just import models.ParentRecord and models.ChildRecord, as I import those forms in my models.py, and thus an error is raised that Django can't import these models. I presume because of circular imports.
So, I try this instead:
# forms.py
from django.db.models import get_model
class ParentRecordForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super (ParentRecordForm, self).__init__(*args, **kwargs)
class Meta:
model = get_model('model', 'ParentRecord')
exclude = ('user')
class ChildRecordForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super (ChildRecordForm, self).__init__(*args, **kwargs)
class Meta:
model = get_model('model', 'ParentRecord')
exclude = ('user')
However, model for these forms always returns None.
I I go and pass ChildRecordForm some totally unrelated model that I can import from a different app in my project, for example:
# forms.py
from another_app import AnotherModel
class ChildRecordForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super (ChildRecordForm, self).__init__(*args, **kwargs)
class Meta:
model = AnotherModel
exclude = ('user')
Then it works, meaning, The form returns the fields of AnotherModel.
So, I can't work out why get_model() works for me in shell, but not in a form class when I use it to declare a value for a model.
回答1:
My guess on get_model()
is that running it at the class-definition level can give incorrect results, since it will get evaulated as Django is populating all the models in it's AppCache. My quick reading of the django.db.models.loading
module doesn't seem to show that issue, but one thing to try is to run get_model()
inside a view and print out the results to see if it is what you think it should be, since by that time the AppCache
should be fully loaded.
But - as a workaround to get around the original circular import (so you don't have to use get_model anyway) is to not do the form imports at the module level - you can stick them in the classmethod instead:
class ParentRecord(models.Model):
@classmethod
def get_form(self, *args, **kwargs):
from yourapp.forms import BreathingActivityRecordForm
return BreathingActivityRecordForm
This way, the import will only be evaulated when you actually call .get_form()
, and there shouldn't be any circular dependencies at module loading tme.
来源:https://stackoverflow.com/questions/9734841/django-how-can-i-use-get-model-in-my-use-case-to-correctly-import-a-class-and-a