Django: How to create a model from a definition in another module - django

Lets say I have this Django setup:
appA - models.py
- views.py
- etc...
global - models.py
What I want is import the models from global.models in appA.models so that they are treated as a normal appA models by syncdb and south.
global.models:
from django.db import models
class Foo(models.Model):
#django model stuff
appA.models:
try 1:
from global.models import *
>>manage.py schemamigration appA --auto
>>does not see Foo
try 2:
from global.models import Foo
class Foo(Foo):
pass
>>manage.py schemamigration appA --auto
>>Error: One or more models did not validate:
>>appA.Foo: 'foo_ptr' has a relation with model <class 'global.models.Foo'>, which has either not been installed or is abstract.
What is the correct way to accomplish this?

from .models import Foo
class Foo(models.Model):
#stuff
class Meta:
abstract = True

global is a python statement, you should not use it to name one of your package. Try using a different name, and don't forget to put a __init__.py file in the directory to turn it into a python package.

Related

Difference between models and Model in django

What exactly is the difference between models and Model.while writing a model in django.
from django.db import models
class Teacher(models.Model):
In your example, Model is the class from which you are inheriting, and models is where that Model class is located.
The models import is a folder, which implicitly runs the directory:
django/db/models/__init__.py
models.Model is a class found in the models folder within base.py. This is because __init__.py in the models folder imports base.py as well.

How/best way to migrate away from an old requirement (django-json-field) with django migration?

I am currently on Django 1.7 and my database is PostgreSQL. I have the following model.
# myapp/models.py
from django.db import models
from json_field import JSONField # using django-json-field
from json_field.fields import JSONDecoder
class MyModel(models.Model):
the_data = JSONField(
decoder_kwargs={'cls': JSONDecoder, 'parse_float': float},
default='[{}]',
)
...
I am now looking to upgrade to Django 1.10 and take advantage of the new(ish) JSONField in django.contrib.postgres.fields.
I change my model to look like this.
# myapp/models.py
from django.db import models
from django.contrib.postgres.fields import JSONField # Now want to use the new JSONField
class MyModel(models.Model):
the_data = JSONField(
default='{}',
)
...
I then create a migration for the app.
./manage.py makemigrations myapp
When it attempts to create a migration it complains...
from json_field.forms import JSONFormField
File "/Users/travismillward/Projects/amcards_env/lib/python2.7/site-packages/json_field/forms.py", line 5, in <module>
from django.forms import fields, util
ImportError: cannot import name util
I understand why it is complaining. django-json-field is not updated for django 1.10 and it wants to import json_field in one of the original migration files. So I can either go back and modify my original migration file that imports json_field but then it won't actually modify the column data type because it thinks it is already done. Or, I have to fix django-json-fields to work with django 1.10 just so the migration can be created. And I will have to leave that requirement in place even though I don't use it, it's just for the migration!
On my last project I just modified the original migration to make it think that it was using django.contrib.postgres.fields.jsonb.JSONField all along. However, after I ran the migration, it didn't change the column's data type from text to jsonb. So I manually did that since it was a smaller project. For this project, I really don't want to manually alter the database.
Any suggestions on how to migrate away from django-json-field gracefully and with a plan to remove it from my code and requirements?

How to register Django models that are only used in tests

I'm writing an app that has a custom model field. I want to test that field, using a model that is only used within tests, but I'm struggling to get the model working in tests.
Some of my app structure is like this:
myapp/
fields.py
models.py
tests/
fields/
models.py
tests.py
settings.py
test_models.py
test_views.py
tests/fields/models.py is like this:
from django.db import models
from myapp.fields import MyCustomField
class MyTestModel(models.Model):
custom_field = MyCustomField()
I then import MyTestModel and try to use it in tests/fields/tests.py.
Things I've tried...
1. Initially I got:
RuntimeError: Model class tests.fields.models.MyTestModel doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
2. So I added "tests", to INSTALLED_APPS in tests/settings.py. But then I get:
django.db.utils.OperationalError: no such table: tests_mytestmodel
3. I've seen this in the docs about isolating model registration in tests. So I've tried moving the models into tests/fields/tests.py:
from django.db import models
from django.test import TestCase
from django.test.utils import isolate_apps
from myapp.fields import MyCustomField
#isolate_apps('tests')
class MyTestCase(TestCase):
def test_things_work(self):
class MyTestModel(models.Model):
custom_field = MyCustomField()
obj = MyTestModel.objects.create(custom_field='foo')
self.assertEqual(...)
But that still gets me:
django.db.utils.OperationalError: no such table: tests_mytestmodel
I've tried looking through the tests of lots of other Django projects that provide custom fields and can't see what I'm missing that (apparently) makes their tests with models work.
It sounds like, somehow, there need to be migrations for these models that are only used in the tests... is that right? How? Or something else?
Since your test app is in a nested folder you need to specify the whole path to it in INSTALLED_APPS instead of the parent folder, like:
INSTALLED_APPS = [
...,
"tests.fields"
]

How to migrate models from a models package hierarchy and not from models.py with SOUTH in Django?

Hy!
I have my models in a hierarchy below "models" package:
models
|-a.py
|-b.py
instead of having all my models into the models.py
But when I run the migration command for South it doesn't find any of them:
schemamigration my_app --auto
In the meta class already exists the app_label='my_app'
I use auto because the tables are already changed.
Have you imported all the models in __init__.py? If you've done that, there's effectively no difference in how it works.

Model in sub-directory via app_label?

In order to place my models in sub-folders I tried to use the app_label Meta field as described here.
My directory structure looks like this:
project
apps
foo
models
__init__.py
bar_model.py
In bar_model.py I define my Model like this:
from django.db import models
class SomeModel(models.Model):
field = models.TextField()
class Meta:
app_label = "foo"
I can successfully import the model like so:
from apps.foo.models.bar_model import SomeModel
However, running:
./manage.py syncdb
does not create the table for the model. In verbose mode I do see, however, that the app "foo" is properly recognized (it's in INSTALLED_APPS in settings.py). Moving the model to models.py under foo does work.
Is there some specific convention not documented with app_label or with the whole mechanism that prevents this model structure from being recognized by syncdb?
See Django ticket #10985: Explain how models can be organised in a directory
It may be that you aren't importing your models into __init__.py?
syncdb will not create tables for models not located in <appname>.models, so import it in there, e.g. from apps.foo.models import SomeModel.
Here is a solution if you have a newer version of Django, supposing you have a subfolder named subfolder :
in apps.py of your folder app:
from django.apps import AppConfig
class MyappConfig(AppConfig):
name = 'myapp'
def ready(self):
from myapp.subfolder import models