【问题标题】:How to establish a One to One relation in django model in mongo db?如何在 mongodb 的 django 模型中建立一对一关系?
【发布时间】:2022-09-23 03:21:18
【问题描述】:

我在 django 中使用 mongo db 和 djongo。我有两个模型EmployeePresentEmployee

员工:

class Employee(models.Model):
    employee_id = models.CharField(primary_key=True, max_length=10, null=False, blank=False)
    employee_name = models.CharField(max_length=200, null=False, blank=False)
    email = models.EmailField(max_length=500, null=True, blank=True)

    def __str__(self):
        return self.employee_name

现任员工:


class PresentEmployee(models.Model):
    employee_id = models.OneToOneField(Employee, on_delete=models.CASCADE)
    present_id = models.IntegerField(null=False, blank=False)
    id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)

    def __str__(self):
        return str(self.employee_id)

当我尝试向PresentEmployee 添加新对象时,出现错误

web_1    | Traceback (most recent call last):
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/query.py\", line 808, in __iter__
web_1    |     yield from iter(self._query)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/query.py\", line 167, in __iter__
web_1    |     yield self._align_results(doc)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/query.py\", line 269, in _align_results
web_1    |     if selected.table == self.left_table:
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/sql_tokens.py\", line 133, in table
web_1    |     return alias2token[name].table
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/sql_tokens.py\", line 133, in table
web_1    |     return alias2token[name].table
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/sql_tokens.py\", line 133, in table
web_1    |     return alias2token[name].table
web_1    |   [Previous line repeated 917 more times]
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/sql_tokens.py\", line 130, in table
web_1    |     name = self.given_table
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/sql_tokens.py\", line 141, in given_table
web_1    |     name = self._token.get_real_name()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/sql.py\", line 361, in get_real_name
web_1    |     return self._get_first_name(dot_idx)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/sql.py\", line 386, in _get_first_name
web_1    |     return token.get_name()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/sql.py\", line 355, in get_name
web_1    |     return self.get_alias() or self.get_real_name()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/sql.py\", line 344, in get_alias
web_1    |     _, ws = self.token_next_by(t=T.Whitespace)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/sql.py\", line 244, in token_next_by
web_1    |     return self._token_matching(funcs, idx, end)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/sql.py\", line 223, in _token_matching
web_1    |     if func(token):
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/sql.py\", line 242, in <lambda>
web_1    |     funcs = lambda tk: imt(tk, i, m, t)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/utils.py\", line 100, in imt
web_1    |     elif types and any(token.ttype in ttype for ttype in types):
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/utils.py\", line 100, in <genexpr>
web_1    |     elif types and any(token.ttype in ttype for ttype in types):
web_1    |   File \"/usr/local/lib/python3.10/site-packages/sqlparse/tokens.py\", line 19, in __contains__
web_1    |     return item is not None and (self is item or item[:len(self)] == self)
web_1    | RecursionError: maximum recursion depth exceeded in comparison
web_1    | 
web_1    | The above exception was the direct cause of the following exception:
web_1    | 
web_1    | Traceback (most recent call last):
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/cursor.py\", line 76, in fetchone
web_1    |     return self.result.next()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/query.py\", line 797, in __next__
web_1    |     result = next(self._result_generator)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/sql2mongo/query.py\", line 830, in __iter__
web_1    |     raise exe from e
web_1    | djongo.exceptions.SQLDecodeError: 
web_1    | 
web_1    |      Keyword: FAILED SQL: SELECT %(0)s AS \"a\" FROM \"employees_employee\" WHERE \"employees_employee\".\"employee_id\" = %(1)s LIMIT 1
web_1    | Params: (1, \'EMP1\')
web_1    | Version: 1.3.6
web_1    |      Sub SQL: None
web_1    |      FAILED SQL: None
web_1    |      Params: None
web_1    |      Version: None
web_1    | 
web_1    | The above exception was the direct cause of the following exception:
web_1    | 
web_1    | Traceback (most recent call last):
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/utils.py\", line 98, in inner
web_1    |     return func(*args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/cursor.py\", line 81, in fetchone
web_1    |     raise db_exe from e
web_1    | djongo.database.DatabaseError
web_1    | 
web_1    | The above exception was the direct cause of the following exception:
web_1    | 
web_1    | Traceback (most recent call last):
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/core/handlers/exception.py\", line 55, in inner
web_1    |     response = get_response(request)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/core/handlers/base.py\", line 197, in _get_response
web_1    |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/contrib/admin/options.py\", line 686, in wrapper
web_1    |     return self.admin_site.admin_view(view)(*args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/utils/decorators.py\", line 133, in _wrapped_view
web_1    |     response = view_func(request, *args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/views/decorators/cache.py\", line 62, in _wrapped_view_func
web_1    |     response = view_func(request, *args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/contrib/admin/sites.py\", line 242, in inner
web_1    |     return view(request, *args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/contrib/admin/options.py\", line 1890, in add_view
web_1    |     return self.changeform_view(request, None, form_url, extra_context)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/utils/decorators.py\", line 46, in _wrapper
web_1    |     return bound_method(*args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/utils/decorators.py\", line 133, in _wrapped_view
web_1    |     response = view_func(request, *args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/contrib/admin/options.py\", line 1750, in changeform_view
web_1    |     return self._changeform_view(request, object_id, form_url, extra_context)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/contrib/admin/options.py\", line 1796, in _changeform_view
web_1    |     form_validated = form.is_valid()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/forms/forms.py\", line 205, in is_valid
web_1    |     return self.is_bound and not self.errors
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/forms/forms.py\", line 200, in errors
web_1    |     self.full_clean()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/forms/forms.py\", line 439, in full_clean
web_1    |     self._post_clean()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/forms/models.py\", line 492, in _post_clean
web_1    |     self.instance.full_clean(exclude=exclude, validate_unique=False)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/base.py\", line 1464, in full_clean
web_1    |     self.clean_fields(exclude=exclude)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/base.py\", line 1516, in clean_fields
web_1    |     setattr(self, f.attname, f.clean(raw_value, self))
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/fields/__init__.py\", line 755, in clean
web_1    |     self.validate(value, model_instance)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/fields/related.py\", line 1090, in validate
web_1    |     if not qs.exists():
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/query.py\", line 1225, in exists
web_1    |     return self.query.has_results(using=self.db)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/sql/query.py\", line 592, in has_results
web_1    |     return compiler.has_results()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/sql/compiler.py\", line 1363, in has_results
web_1    |     return bool(self.execute_sql(SINGLE))
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/models/sql/compiler.py\", line 1406, in execute_sql
web_1    |     val = cursor.fetchone()
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/utils.py\", line 97, in inner
web_1    |     with self:
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/utils.py\", line 91, in __exit__
web_1    |     raise dj_exc_value.with_traceback(traceback) from exc_value
web_1    |   File \"/usr/local/lib/python3.10/site-packages/django/db/utils.py\", line 98, in inner
web_1    |     return func(*args, **kwargs)
web_1    |   File \"/usr/local/lib/python3.10/site-packages/djongo/cursor.py\", line 81, in fetchone
web_1    |     raise db_exe from e
web_1    | django.db.utils.DatabaseError

如何建立从 Employee 模型到 PresentEmployee 模型的一对一关系。就像 sql db 中的 OneToOneField 一样,比如 postgresql。

注意:不要介意web_1 |,这是因为我使用的是docker。

    标签: django mongodb django-models


    【解决方案1】:

    如果你使用 djongo,你可以创建 EmbeddedField 类:

    class EmbeddedField(MongoField):
        def __init__(
            self,
            model_container: typing.Type[Model],
            model_form_class: typing.Type[forms.ModelForm] = None,
            model_form_kwargs: dict = None,
            *args, 
            **kwargs
       ):
    

    之后,使用您的示例,您可以创建类似这样的内容

    class Employee(models.Model):
        employee_id = models.ObjectIdField()
        employee_name = models.CharField(max_length=200, null=False, blank=False)
        email = models.EmailField(max_length=500, null=True, blank=True)
    
        def __str__(self):
            return self.employee_name
    
    class PresentEmployee(models.Model):
        present_id = models.ObjectIdField()
        employee = models.EmbeddedField(model_container=Employee)
        id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
    
        def __str__(self):
            return str(self.employee_id)
    

    【讨论】:

      猜你喜欢
      • 2013-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多