我在settings.py
('default'和'banco1')中定义了两个不同的数据库连接。
然后在某些视图中,我收到一个POST,其中包含一些我要针对我创建的ModelForm
进行验证的数据:
product_form = ProductForm(request.POST)
if product_form.is_valid():
产品型号:
class Product(models.Model):
name = models.CharField(max_length=125, blank=False, null=False)
description = models.CharField(max_length=255, blank=True)
abbreviation = models.CharField(max_length=15, blank=True)
category = models.ForeignKey('inventory.Category',
on_delete=models.SET_NULL, null=True, blank=True)
metric = models.CharField(max_length=15, blank=True, null=True)
表格:
class ProductForm(ModelForm):
class Meta:
model = Product
fields = ['name', 'description', 'abbreviation', 'category', 'metric']
观点:
def create(request):
if request.method != 'POST':
return JsonResponse('Operação inválida', safe=False)
product_form = ProductForm(request.POST)
if product_form.is_valid():
f = product_form.save(commit = False)
f.save(using=request.session['database'])
return HttpResponse("Novo product salvo com sucesso")
else:
return HttpResponse("Impossível salvar product. Verifique os campos")
产品模型总是保存在'banco1'数据库中,因此应该从'banco1'数据库中查询FK验证,但每当我尝试使用product_form.is_valid()
进行验证时,Django会尝试查询'default'数据库并抛出验证错误,因为'default'数据库中无法满足FK约束。
如何设置模型表单以使其验证再次成为手动选择的数据库?
修改
建议我使用DB ROUTER模式来选择正确的数据库配置,这样可以正常工作。我的问题是,这个选择应该基于一些标准而不仅仅是模型。如何将视图中的某些变量传递给我的db路由器类中的db_for_read
方法?
EDIT2
新的ProductForm类
class ProductForm(ModelForm):
class Meta:
model = Product
fields = ['name', 'description', 'abbreviation', 'category', 'metric']
def __init__(self,database):
category = forms.ModelChoiceField(queryset=Category.objects.using(database).all())
尝试在我的视图中实例化表单,如下所示:
product_form = ProductForm(request.POST, request.session['database'])
这给了我一个错误:
init ()需要2个位置参数,但有3个被赋予
我知道我的方式无法覆盖__init__
方法,但是我想在python中实现这一点。
编辑3
上次错误:
回溯:
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 2015年\项目\ GIMS \ GIMS \ ENV \ LIB \站点包\ Django的\核心\处理器\ base.py” 在get_response中 149. response = self.process_exception_by_middleware(e,request)
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 2015年\项目\ GIMS \ GIMS \ ENV \ LIB \站点包\ Django的\核心\处理器\ base.py” 在get_response中 147. response = wrapped_callback(request,* callback_args,** callback_kwargs)
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 在创建中2015 \ Projects \ gims \ gims \ gims \ apps \ inventory \ views.py“ 247.如果product_form.is_valid():
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 2015年\项目\ GIMS \ GIMS \ ENV \ LIB \站点包\ Django的\形式\ forms.py” 在is_valid 161.返回self.is_bound而不是self.errors
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 2015年\项目\ GIMS \ GIMS \ ENV \ LIB \站点包\ Django的\形式\ forms.py” 在错误 153. self.full_clean()
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 2015年\项目\ GIMS \ GIMS \ ENV \ LIB \站点包\ Django的\形式\ forms.py” 在full_clean 362. self._clean_fields()
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 2015年\项目\ GIMS \ GIMS \ ENV \ LIB \站点包\ Django的\形式\ forms.py” 在_clean_fields 374. value = field.widget.value_from_datadict(self.data,self.files, self.add_prefix(名))
文件“C:\ Users \ Pavarine \ Documents \ Visual Studio 2015年\项目\ GIMS \ GIMS \ ENV \ LIB \站点包\ Django的\形式\ widgets.py” 在value_from_datadict中 231. return data.get(name)
异常类型:/ inventory / product / create异常时的AttributeError 值:'tuple'对象没有属性'get'
答案 0 :(得分:3)
要启用路由器,只需将其添加到DATABASE_ROUTERS
中的setting.py
,请参阅此处的详细信息:https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#using-routers
每个路由器方法获取hints
字典,该字典应包含表示正在使用的模型实例的instance
键。根据您希望从视图中获取的信息,您可能会很好地使用实例属性中的信息。见这里:https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#topics-db-multi-db-hints。
即:
def db_for_read(self, model, **hints):
model_instance = hints.get('instance')
if model_instance is not None:
pass
#perform actions with model_instance attributes
return None
除此之外,我认为没有其他直接的方法可以将信息从活动视图传递到路由器,因为路由器应该使用模型并根据所使用的模型做出决策。
数据库路由器用于模型层中的自动数据库选择,但模型方法允许手动选择数据库。请参阅此处的示例:https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#manually-selecting-a-database
所以另一个解决方案是重新定义表单类的方法,即save()
(请参阅https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/#the-save-method),并手动保存表单数据,指定要与using
参数一起使用的数据库。即:
class ProductForm(ModelForm):
class Meta:
...
def save(self, commit=True):
product_to_save=super(ProductForm, self).save(commit=False)
#the above creates product_to_save instance, but doesn't saves it to DB
product_to_save.save(using=='banco1')
return product_to_save
在评论中,我建议将需要对其他数据库进行验证的字段进行子类化,但是可能更简单的方法......因为它是FK字段,它可能是接受{ModelChoiceField
的{{1}}实例。 1}}构造函数中的参数,所以你可以提供它,即:
queryset
请参阅:https://docs.djangoproject.com/en/1.9/ref/forms/fields/#fields-which-handle-relationships
回答EDIT2
重新定义构造函数的方式class ProductForm(ModelForm):
category_field = forms.ModelMultipleChoiceField(queryset=Category.objects.using('banco1'))
...
参数获取database
和request.POST
未映射到任何内容,这就是您收到错误的原因。
您应该考虑其他参数并调用超类构造函数,否则您将破坏MRO,所以这样的事情应该可以完成这项任务:
request.session['database']
然后照常使用命名参数:
class ProductForm(ModelForm):
...
def __init__(self, *args, db_to_use='default', **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
#category = forms.ModelChoiceField(queryset=Category.objects.using(db_to_use).all())
#the below line suggested as improvement by Alasdair and confirmed as working by Pavarine, so I updated the answer here
self.fields['category'].queryset = Category.objects.using(database).all()