Django: How can I use get_model in my use case to correctly import a class and avoid conflicts

蓝咒 提交于 2019-12-23 04:18:25

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!