Django сложное строковое представление модельного объекта (def __str __ (self) :) - PullRequest
0 голосов
/ 24 апреля 2018

Я уже некоторое время использую 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() объекты в модели.)

Pic of it working

Так что я должен быть в состоянии сделать то же самое для SnComplex, верно?После того, как каждая модель имеет одинаковое отношение к RadioSn в соответствующих столбцах sn, и представление str объектов RadioSn сделано для этой модели.

Нет, это то, что я получаю.

Error The line that crashes it

Если я просто представляю 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.

1 Ответ

0 голосов
/ 24 апреля 2018

Я рассматривал проблему, с которой вы столкнулись, и подумал, что это может быть внутренняя ошибка соединения. Я посмотрел на базу данных (не управляемую django) и оказалось, что radio_sn.role не установлен как внешний ключ.

Учитывая, что можно было иметь "плохую" роль, связанную с конкретным датчиком. Похоже, что существовала запись устаревшего серийного номера с ролью, которой не было в таблице ролей, которая была основной причиной ошибки соединения и ошибки «без роли», которую вы получили.

Я исправил эти записи и расскажу, как сделать radio_sn.role внешним ключом для таблицы ролей.

...