2👍
You could make a view in the database that has the cross database query in it, then define the model for the view in a separate file to keep syncdb working.
Happy programming. 🙂
2👍
I know that Djano-nosql has support for keys and such though some magic from http://www.allbuttonspressed.com/projects/django-dbindexer. Maybe some of that could help.
From the description:
“you can just tell the dbindexer which models and fields should support these queries and it’ll take care of maintaining the required indexes for you.”
-Kerry
- [Django]-How can I filter a Django query with a list of values?
- [Django]-Django: using <select multiple> and POST
- [Django]-Django – view sql query without publishing migrations
2👍
As to the ForeignKeyAcrossDb
part, couldn’t you possibly make some adjustments to your class inside __init__
? Check if the appropriate field is Integer
if not, load it from the database, or do anything else that is required. Python __class__
es can be changed at runtime without much problem.
- [Django]-ImproperlyConfigured: You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings
- [Django]-Automated django receive hook on server: respond to collectstatic with "yes"
- [Django]-Substring in a django template?
2👍
After breaking my head some days, I managed to get my Foreign Key ON THE SAME BANK!
Can be made a change over the FORM to seek a FOREIGN KEY in a different bank!
First, add a RECHARGE of FIELDS, both directly (crack) my form, in function ____init____
app.form.py
# -*- coding: utf-8 -*-
from django import forms
import datetime
from app_ti_helpdesk import models as mdp
#classe para formulario de Novo HelpDesk
class FormNewHelpDesk(forms.ModelForm):
class Meta:
model = mdp.TblHelpDesk
fields = (
"problema_alegado",
"cod_direcionacao",
"data_prevista",
"hora_prevista",
"atendimento_relacionado_a",
"status",
"cod_usuario",
)
def __init__(self, *args, **kwargs):
#-------------------------------------
# using remove of kwargs
#-------------------------------------
db = kwargs.pop("using", None)
# CASE use Unique Keys
self.Meta.model.db = db
super(FormNewHelpDesk, self).__init__(*args,**kwargs)
#-------------------------------------
# recreates the fields manually
from copy import deepcopy
self.fields.update(deepcopy( forms.fields_for_model( self.Meta.model, self.Meta.fields, using=db ) ))
#
#-------------------------------------
#### follows the standard template customization, if necessary
self.fields['problema_alegado'].widget.attrs['rows'] = 3
self.fields['problema_alegado'].widget.attrs['cols'] = 22
self.fields['problema_alegado'].required = True
self.fields['problema_alegado'].error_messages={'required': 'Necessário informar o motivo da solicitação de ajuda!'}
self.fields['data_prevista'].widget.attrs['class'] = 'calendario'
self.fields['data_prevista'].initial = (datetime.timedelta(4)+datetime.datetime.now().date()).strftime("%Y-%m-%d")
self.fields['hora_prevista'].widget.attrs['class'] = 'hora'
self.fields['hora_prevista'].initial =datetime.datetime.now().time().strftime("%H:%M")
self.fields['status'].initial = '0' #aberto
self.fields['status'].widget.attrs['disabled'] = True
self.fields['atendimento_relacionado_a'].initial = '07'
self.fields['cod_direcionacao'].required = True
self.fields['cod_direcionacao'].label = "Direcionado a"
self.fields['cod_direcionacao'].initial = '2'
self.fields['cod_direcionacao'].error_messages={'required': 'Necessário informar para quem é direcionado a ajuda!'}
self.fields['cod_usuario'].widget = forms.HiddenInput()
calling the Form from the View
app.view.py
form = forms.FormNewHelpDesk(request.POST or None, using=banco)
Now, the change in the source Code DJANGO
Only fields of type ForeignKey, ManyToManyField and OneToOneField can use the ‘using’, so added an IF …
django.forms.models.py
# line - 133: add using=None
def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=None, using=None):
# line - 159
if formfield_callback is None:
#----------------------------------------------------
from django.db.models.fields.related import (ForeignKey, ManyToManyField, OneToOneField)
if type(f) in (ForeignKey, ManyToManyField, OneToOneField):
kwargs['using'] = using
formfield = f.formfield(**kwargs)
#----------------------------------------------------
elif not callable(formfield_callback):
raise TypeError('formfield_callback must be a function or callable')
else:
formfield = formfield_callback(f, **kwargs)
ALTER FOLLOW FILE
django.db.models.base.py
alter
# line 717
qs = model_class._default_manager.filter(**lookup_kwargs)
for
# line 717
qs = model_class._default_manager.using(getattr(self, 'db', None)).filter(**lookup_kwargs)
Ready 😀
- [Django]-Handling race condition in model.save()
- [Django]-How do I raise a Response Forbidden in django
- [Django]-Django: best practice way to get model from an instance of that model
1👍
A foreign key field implies that you can
– query on the relationship by joining ie fruit__name
– check referential integrity
– ensure referential integrity upon deletes
– admin raw id lookup functionality
– (some more…)
The first use case would always be problematic.
Probably there are some other foreign key special cases in the codebase which also wouldn’t work.
I run a rather large django site and we are currently using a plain integerfield.
For now i would think subclassing the integerfield and adding the id to object conversion would be easiest (in 1.2 that required patching some bits of django, hope that improved by now)
Will let you know what solution we find.
- [Django]-.filter() vs .get() for single object? (Django)
- [Django]-How can I run a celery periodic task from the shell manually?
- [Django]-How to set up a PostgreSQL database in Django
1👍
Ran into a similar problem of needing to reference (mostly) static data across multiple (5) databases. Made a slight update to the ReversedSingleRelatedObjectDescriptor to allow setting the related model. It doesn’t implement the reverse relationship atm.
class ReverseSingleRelatedObjectDescriptor(object):
"""
This class provides the functionality that makes the related-object managers available as attributes on a model
class, for fields that have a single "remote" value, on the class that defines the related field. Used with
LinkedField.
"""
def __init__(self, field_with_rel):
self.field = field_with_rel
self.cache_name = self.field.get_cache_name()
def __get__(self, instance, instance_type=None):
if instance is None:
return self
try:
return getattr(instance, self.cache_name)
except AttributeError:
val = getattr(instance, self.field.attname)
if val is None:
# If NULL is an allowed value, return it
if self.field.null:
return None
raise self.field.rel.to.DoesNotExist
other_field = self.field.rel.get_related_field()
if other_field.rel:
params = {'%s__pk' % self.field.rel.field_name: val}
else:
params = {'%s__exact' % self.field.rel.field_name: val}
# If the related manager indicates that it should be used for related fields, respect that.
rel_mgr = self.field.rel.to._default_manager
db = router.db_for_read(self.field.rel.to, instance=instance)
if getattr(rel_mgr, 'forced_using', False):
db = rel_mgr.forced_using
rel_obj = rel_mgr.using(db).get(**params)
elif getattr(rel_mgr, 'use_for_related_fields', False):
rel_obj = rel_mgr.using(db).get(**params)
else:
rel_obj = QuerySet(self.field.rel.to).using(db).get(**params)
setattr(instance, self.cache_name, rel_obj)
return rel_obj
def __set__(self, instance, value):
if instance is None:
raise AttributeError("%s must be accessed via instance" % self.field.name)
# If null=True, we can assign null here, but otherwise the value needs to be an instance of the related class.
if value is None and self.field.null is False:
raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
(instance._meta.object_name, self.field.names))
elif value is not None and not isinstance(value, self.field.rel.to):
raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
(value, instance._meta.object_name, self.field.name, self.field.rel.to._meta.object_name))
elif value is not None:
# Only check the instance state db, LinkedField implies that the value is on a different database
if instance._state.db is None:
instance._state.db = router.db_for_write(instance.__class__, instance=value)
# Is not used by OneToOneField, no extra measures to take here
# Set the value of the related field
try:
val = getattr(value, self.field.rel.get_related_field().attname)
except AttributeError:
val = None
setattr(instance, self.field.attname, val)
# Since we already know what the related object is, seed the related object caches now, too. This avoids another
# db hit if you get the object you just set
setattr(instance, self.cache_name, value)
if value is not None and not self.field.rel.multiple:
setattr(value, self.field.related.get_cache_name(), instance)
and
class LinkedField(models.ForeignKey):
"""
Field class used to link models across databases. Does not ensure referrential integraty like ForeignKey
"""
def _description(self):
return "Linked Field (type determined by related field)"
def contribute_to_class(self, cls, name):
models.ForeignKey.contribute_to_class(self, cls, name)
setattr(cls, self.name, ReverseSingleRelatedObjectDescriptor(self))
if isinstance(self.rel.to, basestring):
target = self.rel.to
else:
target = self.rel.to._meta.db_table
cls._meta.duplicate_targets[self.column] = (target, "o2m")
def validate(self, value, model_instance):
pass
- [Django]-Django: Multiple forms possible when using FormView?
- [Django]-Django: guidelines for speeding up template rendering performance
- [Django]-Using Django time/date widgets in custom form
1👍
This solution is originally written for one managed database with migrations and one or more legacy databases with models Meta managed=False
connected at database level to the same database. If a db_table
option contains a database name plus table name quoted correctly by ‘ ` ‘ (MySQL) or by ‘ ” ‘ (other db), e.g. db_table = '"DB2"."table_b"'
, then it is not quoted any more by Django. Queries are compiled by Django ORM correctly, even with JOINs:
class TableB(models.Model):
....
class Meta:
db_table = '`DB2`.`table_b`' # for MySQL
# db_table = '"DB2"."table_b"' # for all other backends
managed = False
Query set:
>>> qs = TableB.objects.all()
>>> str(qs.query)
'SELECT "DB2"."table_b"."id" FROM DB2"."table_b"'
That is supported by all db backends in Django.
(It seems that I started a bounty on a duplicate new question where my answer continues.)
- [Django]-Using {% url ??? %} in django templates
- [Django]-Django: Multiple forms possible when using FormView?
- [Django]-ModuleNotFoundError: No module named 'grp' on windows
0👍
Inspired by @Frans ‘ comment. My workaround is to do this in business layer. In the example given this question. I would set fruit to an IntegerField
on Article
, as “not to do integrity check in data layer”.
class Fruit(models.Model):
name = models.CharField()
class Article(models.Model):
fruit = models.IntegerField()
intro = models.TextField()
Then honor reference relation in application code (business layer). Take Django admin for example, in order to display fruit as a choice in Article’s add page, you populate a list of choices for fruit manually.
# admin.py in App article
class ArticleAdmin(admin.ModelAdmin):
class ArticleForm(forms.ModelForm):
fields = ['fruit', 'intro']
# populate choices for fruit
choices = [(obj.id, obj.name) for obj in Fruit.objects.all()]
widgets = {
'fruit': forms.Select(choices=choices)}
form = ArticleForm
list_diaplay = ['fruit', 'intro']
Of course you may need to take care of form field validation (integrity check).
- [Django]-Django Many-to-Many (m2m) Relation to same model
- [Django]-Pass request context to serializer from Viewset in Django Rest Framework
- [Django]-How to log all sql queries in Django?
0👍
I have a new solution for django v1.10. There are two parts. It works with django.admin and django.rest-framework.
- Inherit the
ForeignKey
class and createForeignKeyAcrossDb
, and override thevalidate()
function, based on this ticket and this post.
class ForeignKeyAcrossDb(models.ForeignKey):
def validate(self, value, model_instance):
if self.remote_field.parent_link:
return
super(models.ForeignKey, self).validate(value, model_instance)
if value is None:
return
using = router.db_for_read(self.remote_field.model, instance=model_instance)
qs = self.remote_field.model._default_manager.using(using).filter(
**{self.remote_field.field_name: value}
)
qs = qs.complex_filter(self.get_limit_choices_to())
if not qs.exists():
raise exceptions.ValidationError(
self.error_messages['invalid'],
code='invalid',
params={
'model': self.remote_field.model._meta.verbose_name, 'pk': value,
'field': self.remote_field.field_name, 'value': value,
}, # 'pk' is included for backwards compatibility
)
- In field declaration, use
db_constraint=False
, for example,
album=ForeignKeyAcrossDb(Singer, db_constraint=False, on_delete=models.DO_NOTHING)
- [Django]-Django character set with MySQL weirdness
- [Django]-Simple Log to File example for django 1.3+
- [Django]-How to add multiple objects to ManyToMany relationship at once in Django ?