class PumpLog(models.Model):
# work_order = models.OneToOneField('WorkOrder', on_delete = models.CASCADE)
work_order = models.ForeignKey('WorkOrder', on_delete = models.CASCADE)
class WorkOrder(models.Model):
completed_on = models.DateField('Completed On', null=True, blank=True)
template_.html
{{ form.work_order|as_crispy_field }}
forms.py
class TempForm(forms.ModelForm):
'''Initializes a mostly blank form with initial values for fields specified in default_values_list'''
initial = {}
page_type = self.page_type
if page_type == 'detail':
data = self.request.POST or None
for default_value in default_values_list:
if default_value in self.kwargs:
initial[default_value] = self.kwargs[default_value]
def clean(self):
...
def __init__(self, *args, **kwargs):
kwargs['initial'] = self.initial
super(TempForm, self).__init__(*args, **kwargs)
form = modelform_factory(model, TempForm,exclude = exclude_list,widgets = widgets)
As you can see there is a FK relationship between PumpLog
and WorkOrder
. When the PumpLog-Update
page loads it only queries the selected/related WorkOrder
. If the drop-down to select the work order is clicked - it queries additional WorkOrder
as the user scrolls or searches.
I am trying to convert it to OneToOne
. But when I switch it to OneToOne
I notice that it retrieves all WorkOrders
- which can take 1-4 minutes to load. I noticed this by placing print(self.index
) in the WorkOrder
__str__
method. In the console I see it list every single WorkOrder
one-by-one. But if I switch it back to FK it only displays the index of the one already selected in the drop-down.
This doesn't seem to be a widget or crispy_form
issue because I see the same behaviour when I remove or revert those.
I understand to some degree that it needs access to all of the work orders so that the user can select whichever one. BUT it doesn't seem to need to load all WorkOrders
when the relationship is FK. Why is it behaving differently when I use OneToOne
?
@markwalker_ pointed out
...django loads all related objects unless you override it.
This guided me to discovering that I had in fact overrode FK drop-downs by default via widgets. This would also explain why I experienced the same sluggishness when commenting out the widgets while using the OneToOne.
In fact if I had commented out the widgets while using the FK relationship I would have seen a similar sluggishness.
The way I override it is first check for any FK fields (which didn't check for OneToOne fields)
def get_foreign_keys(model):
foreign_keys = []
for field in model._meta.fields:
if field.get_internal_type() == 'ForeignKey':
foreign_keys.append(field)
return foreign_keys
...
foreign_keys = get_foreign_keys(model)
I then use the autocomplete ModelSelect2
widget which handles the lazy loading which I took for granted:
for fk in foreign_keys:
widgets[field_name] = autocomplete.ModelSelect2(url = url, forward=forward)
My quick-and-dirty solution is to check for OneToOne fields in get_foreign_keys():
def get_foreign_keys(model):
foreign_keys = []
for field in model._meta.fields:
if field.get_internal_type() == 'ForeignKey':
foreign_keys.append(field)
elif field.get_internal_type() == 'OneToOneField':
foreign_keys.append(field)
print(field.get_internal_type())
return foreign_keys
A more long term solution will simply be refactoring some naming to accommodate both FK and O2O for that function. And also some additional documentation - so I can better navigate old code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.