Я уже некоторое время использую str для обработки удобочитаемых имен для объектов модели, но недавно я столкнулся с некоторыми странными сбоями и ошибками, которые, по-видимому, связаны сэта функция.
У меня есть две модели SensorAssignment
и SnComplex
, обе имеют связи OneToOne со столбцом в третьей модели RadioSn
.RadioSn
- главный пул всех серийных номеров.SnComplex
- это список сериалов, назначенных клиенту, а SensorAssignment
обрабатывает метаданные для сериала клиента, назначенного определенному физическому местоположению.
Важно отметить, что это устаревшая БД, которую я унаследовал,Некоторые отношения не идеальны ИМХО.
Ниже приведены упрощенные версии моделей только с соответствующими столбцами.
RadioSn
class RadioSn(models.Model):
sn = models.AutoField(primary_key=True)
role = models.ForeignKey('Roles', db_column='role', on_delete=models.DO_NOTHING)
class Meta:
managed = False
db_table = 'radio_sn'
ordering = ['sn']
def __str__(self):
return '%s -- %s' % (self.sn, self.role)
SnComplex
class SnComplex(models.Model):
sn = models.OneToOneField(RadioSn, on_delete=models.DO_NOTHING, db_column='sn', primary_key=True)
complex = models.ForeignKey(Complex, on_delete=models.DO_NOTHING, db_column='complex')
class Meta:
managed = False
db_table = 'sn_complex'
SensorAssignment
class SensorAssignment(models.Model):
unit = models.ForeignKey('Unit', on_delete=models.DO_NOTHING, db_column='unit')
sn = models.OneToOneField(RadioSn, on_delete=models.DO_NOTHING, db_column='sn')
class Meta:
managed = False
db_table = 'sensor_assignment'
ordering = ['sn']
def __str__(self):
return self.pk
Здесь мы начинаем сталкиваться с моей проблемой.Я использую form.ModelForm
для управления созданием и обслуживанием SensorAssignment
объектов.Таким образом, для поля sn
создается html <select>
с возможностью выбора RadioSn
объектов, которые представлены в формате str, указанном выше (строка, состоящая из первичного ключа int sn
и внешнего ключа role
[ИМХО плохое именование]).
Это работает отлично (я ограничиваю наборы запросов соответствующими параметрами при инициализации формы в представлении, поэтому это не all()
объекты в модели.)
Так что я должен быть в состоянии сделать то же самое для SnComplex
, верно?После того, как каждая модель имеет одинаковое отношение к RadioSn
в соответствующих столбцах sn
, и представление str
объектов RadioSn
сделано для этой модели.
Нет, это то, что я получаю.
Если я просто представляю RadioSn
объекты как self.sn
вместо объединения self.sn
иself.role
он работает в обеих формах, но если я оставлю его сцепленным, это приведет к сбою формы SnComplex
.Все RadioSn
объекты имеют значение роли.
Есть идеи, что происходит?У нас есть строковое представление RadioSn
объектов модели, которые сбивают SnComplex
ModelForm
при рендеринге шаблона, но отлично работают на нескольких версиях SensorAssignment
ModelForm
в других местах.
Запрошенная форма SnComplex:
class AddSensorForm(forms.ModelForm):
class Meta:
model = SnComplex
fields = '__all__'
Полный возврат:
Request Method: GET
Request URL: http://127.0.0.1/complex/33/
Django Version: 2.0.4
Python Version: 3.6.1
Installed Applications:
['apps.dashboard',
'rest_framework',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'apps.dashboard.templatetags.custom_filters',
'widget_tweaks',
'phonenumber_field',
'pygal',
'django_filters']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Template error:
In template C:\git\si-dash\apps\dashboard\templates\header.html, error at line 0
Roles matching query does not exist.
1 : {% load static %}
2 : {% load widget_tweaks %}
3 : {% load custom_filters %}
4 : {% csrf_token %}
5 :
6 : <!DOCTYPE html>
7 : <html lang="en">
8 :
9 : <head>
10 : <meta charset="utf-8">
Traceback:
File "C:\Python36\lib\site-packages\django\db\models\fields\related_descriptors.py" in __get__
158. rel_obj = self.field.get_cached_value(instance)
File "C:\Python36\lib\site-packages\django\db\models\fields\mixins.py" in get_cached_value
13. return instance._state.fields_cache[cache_name]
During handling of the above exception ('role'), another exception occurred:
File "C:\Python36\lib\site-packages\django\core\handlers\exception.py" in inner
35. response = get_response(request)
File "C:\Python36\lib\site-packages\django\core\handlers\base.py" in _get_response
128. response = self.process_exception_by_middleware(e, request)
File "C:\Python36\lib\site-packages\django\core\handlers\base.py" in _get_response
126. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Python36\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view
21. return view_func(request, *args, **kwargs)
File "C:\git\si-dash\apps\dashboard\views\complex.py" in complex
179. return render(request, 'design/complex.html', passed_data)
File "C:\Python36\lib\site-packages\django\shortcuts.py" in render
36. content = loader.render_to_string(template_name, context, request, using=using)
File "C:\Python36\lib\site-packages\django\template\loader.py" in render_to_string
62. return template.render(context, request)
File "C:\Python36\lib\site-packages\django\template\backends\django.py" in render
61. return self.template.render(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render
175. return self._render(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)
File "C:\Python36\lib\site-packages\django\template\loader_tags.py" in render
155. return compiled_parent._render(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in _render
167. return self.nodelist.render(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)
File "C:\Python36\lib\site-packages\django\template\loader_tags.py" in render
67. result = block.nodelist.render(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)
File "C:\Python36\lib\site-packages\django\template\defaulttags.py" in render
314. return nodelist.render(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render
943. bit = node.render_annotated(context)
File "C:\Python36\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)
File "C:\Python36\lib\site-packages\django\template\defaulttags.py" in render
211. nodelist.append(node.render_annotated(context))
File "C:\Python36\lib\site-packages\django\template\base.py" in render_annotated
910. return self.render(context)
File "C:\Python36\lib\site-packages\widget_tweaks\templatetags\widget_tweaks.py" in render
187. return str(bounded_field)
File "C:\Python36\lib\site-packages\django\utils\html.py" in <lambda>
380. klass.__str__ = lambda self: mark_safe(klass_str(self))
File "C:\Python36\lib\site-packages\django\forms\boundfield.py" in __str__
36. return self.as_widget()
File "C:\Python36\lib\site-packages\widget_tweaks\templatetags\widget_tweaks.py" in as_widget
31. html = old_as_widget(widget, attrs, only_initial)
File "C:\Python36\lib\site-packages\widget_tweaks\templatetags\widget_tweaks.py" in as_widget
31. html = old_as_widget(widget, attrs, only_initial)
File "C:\Python36\lib\site-packages\widget_tweaks\templatetags\widget_tweaks.py" in as_widget
31. html = old_as_widget(widget, attrs, only_initial)
File "C:\Python36\lib\site-packages\django\forms\boundfield.py" in as_widget
118. **kwargs
File "C:\Python36\lib\site-packages\django\forms\widgets.py" in render
234. context = self.get_context(name, value, attrs)
File "C:\Python36\lib\site-packages\django\forms\widgets.py" in get_context
677. context = super().get_context(name, value, attrs)
File "C:\Python36\lib\site-packages\django\forms\widgets.py" in get_context
637. context['widget']['optgroups'] = self.optgroups(name, context['widget']['value'], attrs)
File "C:\Python36\lib\site-packages\django\forms\widgets.py" in optgroups
585. for index, (option_value, option_label) in enumerate(self.choices):
File "C:\Python36\lib\site-packages\django\forms\models.py" in __iter__
1141. yield self.choice(obj)
File "C:\Python36\lib\site-packages\django\forms\models.py" in choice
1147. return (self.field.prepare_value(obj), self.field.label_from_instance(obj))
File "C:\Python36\lib\site-packages\django\forms\models.py" in label_from_instance
1213. return str(obj)
File "C:\git\si-dash\apps\dashboard\models.py" in __str__
728. return '%s -- %s' % (self.sn, self.role)
File "C:\Python36\lib\site-packages\django\db\models\fields\related_descriptors.py" in __get__
164. rel_obj = self.get_object(instance)
File "C:\Python36\lib\site-packages\django\db\models\fields\related_descriptors.py" in get_object
139. return qs.get(self.field.get_reverse_related_filter(instance))
File "C:\Python36\lib\site-packages\django\db\models\query.py" in get
403. self.model._meta.object_name
Exception Type: DoesNotExist at /complex/33/
Exception Value: Roles matching query does not exist.