4

I'm currently writing the tests for our django application. Sadly we had to use a multiple database layout and can't change this. (Distributed databases with multiple backends on different servers across multiple datacenters)

We have two databases:

  1. default databases with django default tables
  2. application databases with some models

For these models we wrote different routers like documented on the django site. Now the problem, if I run python manage.py test customerreceipts the test framework dies after some seconds with the following error:

django.db.utils.ProgrammingError: relation "auth_user" does not exist

I checked the created database and there were no tables. Because of this a query from a model throws the error.

The problem model is (in database 2):

class CustomerReceipts(models.Model):

    def _choices_user():
        users = User.objects.all()
        users = users.order_by('id')
        return [(e.id, e.username) for e in users]

    # General
    receipt_name = models.CharField(max_length=20, verbose_name="Receipt name")  #: Receipt name
    ....

    # Auditing
    owner = models.IntegerField(verbose_name="Owner", choices=[('', '')] + _choices_user())

Because multiple database setup does not support direct links, we use an IntegerField for the owner and the business logic handles the integrity.

The problem is the _choices_user() which sets up an query for the missing table. What I don't understand is why django does not create the table auth_user in the first run. If I remove the app with the causing model, the test framework is working without any problem.

Any ideas how this can be fixed?

Thanks!

Edit: I created a one database setup and tried the same thing. Sadly it throws the same error! I'm confused now. Can someone test this too? Create a model with _choices_user method and run test.

MAGYS
  • 181
  • 1
  • 14
  • Added a bug report on django project https://code.djangoproject.com/ticket/22864#ticket. – MAGYS Jun 18 '14 at 17:49

2 Answers2

1

You can manually select the database. Just call using(). Method using() takes a single argument: the alias of the database on which you want to run the query.

def _choices_user():
    users = User.objects.using('default').all()
    .....
    .....

Django 1.7 docs

Sultan
  • 834
  • 1
  • 8
  • 16
0

This is not exactly a perfect answer but the only way currently:

Model (removed choices):

class CustomerReceipts(models.Model):
    # General
    receipt_name = models.CharField(max_length=20, verbose_name="Receipt name")  #: Receipt name
    ....

    # Auditing
    owner = models.IntegerField(verbose_name="Owner")

Admin:

class CustomerReceiptsAdminForm(forms.ModelForm):
    class Meta:
        model = CustomerReceipts

    users = forms.ChoiceField()

    def __init__(self, *args, **kwargs):
        super(CustomerReceiptsAdminForm, self).__init__(*args, **kwargs)
        owner = self.instance.owner
        usersAll = User.objects.all()
        usersAll = usersAll.order_by('id')
        available_choices = [(e.id, e.username) for e in usersAll]
        self.fields['users'].choices = available_choices
        self.fields['users'].initial = owner

class CustomerReceipts(admin.ModelAdmin):
    fields = ('abc', 'users')
    list_display = ('abc', 'get_user')

    form = CustomerReceiptsAdminForm

    def save_model(self, request, obj, form, change):
        obj.owner = form.cleaned_data['users']
        obj.save()

    def get_user(self, obj):
        return User.objects.get(id=obj.owner).username
    get_user.short_description = 'User'

This will handle all displaying in the admin view and selects the right customer upon editing.

MAGYS
  • 181
  • 1
  • 14