问题描述
我正在编写一个基于django-nonrel的应用程序,并使用Django提供的管理员视图功能。我想要一个多对多两个模型之间的关系
,为此,我使用 djangotoolbox.fields
中的 ListField
要提供自定义表单字段,我已经覆盖了另一个类ModelListField的ListField,如覆盖了formfield函数以返回一个MultipleChoiceField窗体小部件。
视图部分工作正常,但无法使用sqlite3后端保存模型。
假设两个模型(笔记和标签之间的标准多对多关系)
从django.db导入
class Tag(models.Model):
name = models.CharField(max_length = 255)
class Note(models.Model):
tags = ModelListField(db.ForeignKey(Tag))
随着这些更改,添加注释页面正确显示在管理界面中,但是当我尝试保存该笔记时,我得到以下异常:
InterfaceError,错误绑定参数0 - 可能不支持的类型
在django\db\backends\sqlite3\base.py中执行,第234行
行234如下所示:
class SQLiteCursorWrapper(Database.Cursor):
Django使用格式样式占位符,但是pysqlite2使用qmark样式
这将修复它 - 但请注意,如果要在查询中使用文字%s,
你需要使用%% s
def execute(self,query,params =()):
query = self.convert_query(query)
try:
234 ---->返回Database.Cursor.execute(self,query,params)
除了Database.IntegrityError,e:
raise utils.IntegrityError,utils.IntegrityError(* tuple(e)),sys.exc_info()[ 2]
除了Database.DatabaseError,e:
raise utils.DatabaseError,utils.DatabaseError(* tuple(e)),sys.exc_info()[2]
查询&传递给通话的参数是:
查询:'INSERT INTOnote(tags)VALUES(?)'
params:[1,2,3]
其中1,2,3是数据库中三个标签字段的pk。
创建模型时,我将标签的COLUMN TYPE指定为ListField,即
CREATE表SQL查询是:
CREATE TABLEnotes(
idinteger NOT NULL PRIMARY KEY,
tagsListField NOT NULL
)
数据库查询执行调用上面的barfs看到列表[1,2,3]。
我尝试将列表作为 smart_unicode(list)
或只是一个字符串1 2 3
但是然后 ListField
在验证(在get_db_prep_value中)时抛出错误,因为它期望列表。
我无法理解将列表对象传递到上面的code> Database.Cursor.execute 调用是否正确,或者当ListField正在正确预期列表但写入时数据库,有人应该将此列表转换为字符串等。?
没有一个很好的例子来说明如何使用ListField :-(
谢谢阅读一段漫长而无聊的描述。
我发现get_db_prep_save有责任以正确的格式准备数据
所以,在ModelListField中,我重写get_db_prep_save并将其转换为字符串以修复不支持的类型错误。
code> def get_db_prep_save (self,value,connection):
retval = super(ModelListField,self).get_db_prep_save(value)
return unicode(retval)
我还面临选择小部件不显示pk> 10的标签的问题。
内部django-non 1.3,
我不得不在下面的函数中添加eval:
class Select
def render_options(self,choices,selected_choices):
** if(type(selected_choices)!= list):
selected_choices = eval(selected_choices)**
这是因为render_option被调用,其中list为string,即[1,2,3],而不是只是[...] 1,2,3],所以使用eval将字符串转换回列表。
不知道这两个是否相关,后一个问题是与django-nonrel的错误。
如dragonx所说,也许这不是一个好主意,用sqlite3和django-nonrel。
我稍后会更改我的后端。
I am writing a django-nonrel based app and using admin view functionality provided by Django.
I want a Many-to-many relationship
between two models and for this, I am using ListField
found inside djangotoolbox.fields
To provide a custom form field, I have overridden ListField with another class ModelListField as described in this question which overrides formfield function to return a MultipleChoiceField form widget.
The view part works fine but I am unable to save the model using sqlite3 backend.
Assume, two models (Standard Many-to-many relationship between note and tags)
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=255)
class Note(models.Model):
tags = ModelListField(db.ForeignKey(Tag))
With these change, add note page appears correctly in admin interface but when I try to save the note, I get the following exception:
InterfaceError, Error binding parameter 0 - probably unsupported type.
inside django\db\backends\sqlite3\base.py in execute, line 234
The line 234 reads as follows:
class SQLiteCursorWrapper(Database.Cursor):
"""
Django uses "format" style placeholders, but pysqlite2 uses "qmark" style.
This fixes it -- but note that if you want to use a literal "%s" in a query,
you'll need to use "%%s".
"""
def execute(self, query, params=()):
query = self.convert_query(query)
try:
234 ----> return Database.Cursor.execute(self, query, params)
except Database.IntegrityError, e:
raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
except Database.DatabaseError, e:
raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
And query & params passed to call are:
query: 'INSERT INTO "note" ("tags") VALUES (?)'
params: [1, 2, 3]
where 1, 2, 3 are pk of three tag fields in database.
When creating model, I specify the COLUMN TYPE of tags as "ListField" i.e.CREATE table SQL query is:
CREATE TABLE "notes" (
"id" integer NOT NULL PRIMARY KEY,
"tags" ListField NOT NULL
)
Database query execute call above barfs when it sees the list [1,2,3].Instead of list, I tried to pass the list as smart_unicode(list)
or just a string "1 2 3"
but then ListField
throws error while validating (in get_db_prep_value) because it expects list.
I am unable to understand whether it is correct to pass the list object to Database.Cursor.execute
call above or something is missing as ListField is correctly expecting list but when writing to database, someone should have converted this list into string etc..?
There's no good example of how to use ListField :-(Thanks for reading a long & boring description..
解决方案 I figured out it is the responsibility of get_db_prep_save to prepare data in correct format for saving to database.So, in ModelListField, I override get_db_prep_save and convert it to string to fix the "Unsupported type" error.
def get_db_prep_save(self, value, connection):
retval = super(ModelListField, self).get_db_prep_save(value)
return unicode(retval)
I also faced an issue with Select Widget not showing tags with pk > 10 as selected.Inside django-non 1.3,I had to add eval in below function:
class Select(Widget):
def render_options(self, choices, selected_choices):
**if(type(selected_choices) != list):
selected_choices = eval(selected_choices)**
This was done because render_option was called with list as string i.e. "[1,2,3]" instead of just [1,2,3], so string was converted back to list using eval.Not sure if these two are related or latter issue is bug with django-nonrel.
As dragonx said, maybe it's not a good idea to test with sqlite3 and django-nonrel.I will change my backend soon.
这篇关于无法使用django admin view将django-toolbox ListField保存到数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!