直接在Django中获取并设置ForeignKey

时间:2015-03-30 21:39:47

标签: django django-models

我正在尝试使用从具有复合外键的mysql数据库创建的Django模型。

我的models.py就是这样。

class Make(models.Model):
    idmake = models.IntegerField(primary_key=True)
    make = models.CharField(max_length=20L, unique=True, blank=True)
    def __unicode__(self):
      return self.make    
    class Meta:
        db_table = 'make'

class Models(models.Model):
    idmodels = models.IntegerField(primary_key=True, unique=True)
    make = models.ForeignKey(Make, db_column='make', to_field='make')
    model = models.CharField(max_length=45L, unique=True)
    resource_type = models.CharField(max_length=7L)
    def __unicode__(self):
      return self.model    
    class Meta:
        db_table = 'models'

class Systems(models.Model):
    idsystems = models.IntegerField(primary_key=True,  unique=True)
    make = models.ForeignKey(Models, null=True, db_column='make', blank=True, related_name='system_make')
    model = models.ForeignKey(Models, null=True, db_column='model', to_field = 'model', blank=True, related_name='system_model')
    serial_num = models.CharField(max_length=45L, blank=True)
    service_tag = models.CharField(max_length=45L, blank=True)
    mac = models.CharField(max_length=45L, unique=True)

现在,当我尝试访问系统的make字段时,我得到ValueError

>>> s = Systems.objects.get(pk=1)
>>> s.model
<Models: model11>
>>> s.model.make
<Make: make1>
>>> s.make
    Traceback (most recent call last):
    File "<console>", line 1, in <module>
    File "/usr/lib/python2.7/site-packages/django/db/models/fields/related.py", line 384, in __get__
      rel_obj = qs.get(**params)
    File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 395, in get
      clone = self.filter(*args, **kwargs)
    File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 669, in filter
      return self._filter_or_exclude(False, *args, **kwargs)
    File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 687, in _filter_or_exclude
      clone.query.add_q(Q(*args, **kwargs))
    File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1271, in add_q
      can_reuse=used_aliases, force_having=force_having)
    File "/usr/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1202, in add_filter 
      connector)
    File "/usr/lib/python2.7/site-packages/django/db/models/sql/where.py", line 71, in add 
      value = obj.prepare(lookup_type, value)
    File "/usr/lib/python2.7/site-packages/django/db/models/sql/where.py", line 339, in prepare
      return self.field.get_prep_lookup(lookup_type, value)
    File "/usr/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 1003, in get_prep_lookup
      return super(IntegerField, self).get_prep_lookup(lookup_type, value)
    File "/usr/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 322, in get_prep_lookup
      return self.get_prep_value(value)
    File "/usr/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 997, in get_prep_value
      return int(value)
    ValueError: invalid literal for int() with base 10: 'make1'

我不允许更改数据库中的表和关系。我是Django的新手,我无法弄清楚这个问题的正确解决方法是什么。基本上我希望能够直接获取并设置make模型的Systems字段。有人可以指导我如何去做这件事吗?我最初的想法是,我必须创建一个自定义ForeignKey字段。

2 个答案:

答案 0 :(得分:0)

我怀疑您的代码与您的数据库架构不符。在这一行:

make = models.ForeignKey(Models, null=True, db_column='make', blank=True, related_name='system_make')

Models应该是Make,不是吗?而您的Systems.modelto_field = 'model',您是否错过to_field='make' Systems.make?我建议您删除整个数据库,运行syncdb并再次创建测试数据。然后看看错误是否仍然存在。

您的代码的其他一些提示:

  • 作为您定义的to_field = 'model'to_field='make',您最好考虑为db_index=Truemake字段添加model。否则,当数据集很大时,查询性能可能会很差

  • 如果您要将Make.makeModels.model设置为唯一且已建立索引,则它们似乎被限定为主键。您的案例中idmakeidmodels是否真的有必要?

  • primary_key=True保证唯一。 unique=True是多余的

  • Django转换使用单数形式进行模型定义。即,使用Model System,而不是Models Systems。另外,通常我们使用id,而不是idmakeidmodels。这些只是转换,由您决定

答案 1 :(得分:0)

我发现了答案,而不是偶然。想与任何面临类似问题的人分享。 直接从make

访问Systems
>>> s = Systems.objects.get(pk=1)
>>> s.model
<Models: model11>
>>> s.model.make
<Make: make1>
>>> s.make_id
u'make1'

直接从make对象

设置Systems
>>> s.make_id = Models.objects.get(model='model21').make.make
>>> s.save()
>>> s.make_id
u'make2'

警告。如果Models的get方法返回多个或没有模型对象,则这将不起作用。例如,如果我的Models表格如下:

enter image description here

然后

>>>> Models.objects.get(model='unknown').make.make
Traceback (most recent call last):
....
MultipleObjectsReturned: get() returned more than one Models -- it returned 2!
>>> Models.objects.get(model='not known').make.make
Traceback (most recent call last):
....
DoesNotExist: Models matching query does not exist.

我认为程序员需要对这些事情保持谨慎。

修改 从@ZZY的评论到这个答案和他自己的答案

class Models(models.Model):
    idmodels = models.IntegerField(primary_key=True, unique=True)
    make = models.ForeignKey(Make, db_column='make', to_field='make')
    model = models.CharField(max_length=45L, unique=True)
    resource_type = models.CharField(max_length=7L)
    def __unicode__(self):
      return self.model    
    class Meta:
        db_table = 'models'
        unique_together = ("make", "model")

由于model中的Models字段是唯一的,因此我描述的方案不应出现在正确的表格中