I'm working with an existing django project that uses south. Within each app there's a models folder where models are stored in different files. I have added a new file (shown below) but when I attempt to create migration files for the model, South fails to detect the new file and says: "Nothing seems to have changed." My question is what is the correct way to get south to detect this new model? Thanks.
from django.contrib.auth.models import User, Group
from django.db import models
from django.contrib import admin
class AdgroupEmailRecipients(models.model):
users = models.ForeignKey(User)
class Meta:
app_label = 'wifipromo'
class AdgroupEmailRecipientsAdmin(admin.ModelAdmin):
list_display = ('user_first_name', 'user_last_name', 'user_email')
def user_first_name(self, obj):
return obj.users.first_name
user_first_name.short_description = "First Name"
def user_last_name(self, obj):
return obj.users.last_name
user_last_name.short_description = "Last Name"
def user_email(self, obj):
return obj.users.email
user_email.short_description = "Email"
In the __init__.py file of the models folder, you have to import the model for South or even syncdb to detect it. Basically django is just looking for one file with all your models... and if you import it all in init.py that's what the system will see.
Related
Model:
from django.db import models
class VilleStation(models.Model):
nomVille = models.CharField(max_length=255)
adresse = models.CharField(max_length=255)
cp = models.CharField(max_length=5)
def __str__(self):
return self.nomVille
admin.py :
from django.contrib import admin
from prixcarbu.models import VilleStation
class VilleStationAdmin(admin.ModelAdmin):
list_display = ('nomVille', 'adresse','cp',)
fields = ('nomVille', 'adresse','cp',)
admin.site.register(VilleStation, VilleStationAdmin)
I imported a CSV file using database browser for SQLite. Table contains the data but admin page doesn't show it.
Do you see empty model in admin or no model at all?
If you don't see your model in the admin at all check if you added your app to INSTALLED_APPS in settings.py.
After closing my computer and reopening, the data is now visible in the admin. Probably a cache problem. Everything is fine now. Thank you all.
I am trying to fork django-oscar to change the dashboard form for product attributes, multioption. Need to have a description field for every option.
project/oscar_fork/catalogue/models.py:
from django.db import models
from django.utils.translation import ugettext_lazy as _
from oscar.apps.catalogue.abstract_models import AbstractAttributeOption, AbstractAttributeOptionGroup
class AbstractAttributeOption(AbstractAttributeOption):
description = models.CharField(_('Description'), max_length=250, blank=True)
group = models.ForeignKey(
'catalogue.AttributeOptionGroup',
on_delete=models.CASCADE,
related_name='optionsblabla',
verbose_name=_("Group"))
from oscar.apps.catalogue.models import *
The models are changed with the extra field "description" in my DB, but still my form field returns cannot find this field.
project/oscar_fork/dashboard/catalogue/forms.py:
from oscar.apps.dashboard.catalogue import forms as base_forms
class AttributeOptionForm(base_forms.AttributeOptionForm):
class Meta(base_forms.AttributeOptionForm.Meta):
fields = ('option', 'description')
If I change the form.py and models.py fields directly in the Oscar app it works. Other forms can be forked that easily as shown above. Tried it with AttributeOptionGroupForm. I think there is a problem with the sequence of import. How can I solve this?
Error:
django.core.exceptions.FieldError: Unknown field(s) (description) specified for AttributeOption
I am using django-oscar v1.6. Django v.2.08.
Your concrete model should be named AttributeOption without the 'Abstract', otherwise oscar will not pick it up and use its own AttributeOption model instead, which has no description:
class AttributeOption(AbstractAttributeOption):
description = ...
You will have to run makemigrations and migrate after that.
Check the source code of the models module that you import at the end. You will see how their dynamic model loading works:
if not is_model_registered('catalogue', 'AttributeOption'):
class AttributeOption(AbstractAttributeOption):
pass
I need to update an existing project to Django 1.5 to take advantage of its newly available custom user model. However, I'm having trouble migrating reusable apps that contain a model with a foreign key to a user. Currently, the foreign key points to auth.User but with a custom user model, it needs to point to myapp.CustomUser. Hence, some kind of migration is needed. I can't simply create a migration file for it because its a reusable app. It wouldn't be future proof because each time the app is updated, I would need to remember to create that migration again (there might even be migration conflicts) so it's not exactly a plausible solution.
Is there a solution to this problem other than to, maybe, fork each project, add a migration file, and then use that instead?
Some code:
models.py in reusable app
from django.conf import settings
from django.db import models
UserModel = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
class ModelA(models.Model):
user = models.ForeignKey(UserModel)
models.py in my project
from django.conf import settings
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
...
settings.py in my project
AUTH_USER_MODEL = 'myapp.CustomUser'
So if the reusable app has a migration that creates a foreign key to a user, the following can be done to support Django 1.5's custom user model.
try:
from django.contrib.auth import get_user_model
except ImportError: # django < 1.5
from django.contrib.auth.models import User
else:
User = get_user_model()
class Migration(SchemaMigration):
def forwards(self, orm):
db.create_table('reusableapp.modela', (
('user', self.gf('django...ForeignKey')(to=orm["%s.%s" % (User._meta.app_label, User._meta.object_name)])
models = {
...
# this should replace "auth.user"
"%s.%s" % (User._meta.app_label, User._meta.module_name): {
'Meta': {'object_name': User.__name__},
}
"reusableapp.modela": {
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s.%s']"% (User._meta.app_label, User._meta.object_name)})
}
}
I'm not sure if this is the best solution but it's being used in apps such as django-reversion.
However, this solution still can pose a problem if you originally started with auth.User and then changed to myapp.customuser, simply because south is honors AUTH_USER_MODEL but the migration for the custom user model hasn't been created yet. This can occur during testing. Ticket #1179 of south addresses this issue (http://south.aeracode.org/ticket/1179).
I have a models folder that has a few models in files that are already in the DB. I have just added another file/model but it is not being added to the DB when I run syncdb. I've tried manage.py validate and it is running fine. I have also run the code and it only fails when it tries to save with "table does not exist".
the original structure was like this:
/models
-- __init__.py
-- file1.py
-- file2.py
and __init__.py looked like:
from file1 import File1Model
from file2 import File2Model
I added file3.py
/models
-- __init__.py
-- file1.py
-- file2.py
-- file3.py
and modified __init__.py
from file1 import File1Model
from file2 import File2Model
from file3 import File3Model
And the contents of file3 (names may have been changed to protect the innocent, but besides that its the exact file):
UPDATE: just tried adding a primary key since the id field may have been messing with the automatically added integer primary key id. Also tried a few variations but no dice.
from django.db import models
from django.contrib.auth.models import User
class File3Model(models.Model):
user = models.OneToOneField(User)
token = models.CharField(max_length=255, blank=False, null=False)
id = models.CharField(primary_key=True, max_length=255)
class Admin:
pass
class Meta:
app_label = 'coolabel'
def __unicode__(self):
return self.user.username
#staticmethod
def getinstance(user, token, id):
try:
instance = File3Model.objects.get(pk=id)
if instance.token != token:
instance.token = token
instance.save()
return instance
except:
pass
instance = File3Model()
instance.user = user
instance.token = token
instance.id = id
instance.save()
return instance
So in this example, File1Model and File2Model are already in the DB and remain in the DB after syncdb. However, File3Model is not added even after rerunning syncdb. Is there any way to figure out why the new model isn't being added??
If you define the model outside of models.py, you have to set the app_label attribute on the models Meta class.
Edit: The app_label has to refer to an app in your INSTALLED_APPS setting. It should probably match the name of the app that the models directory is in, unless you've got a really good reason to do otherwise. That seems to have been your problem here.
class File3Model(models.Model):
foo = models.CharField(...)
...
class Meta:
app_label = "my_app"
Note that syncdb will never remove any tables from the db. The other tables were probably created with syncdb before the models.py was replaced with the directory structure.
set app_label to my app solves my problem.
Why did you split you models and having models folder instead of placing models in models.py ?
In my own project there are about 10 models live in models.py and I'm fine with it.
You can also try manage.py syncdb --all.
And I think its better to keep all models in one single file and import them like from my_app.models import model_name instead of keeping in mind to import necessary model into models/__init__.py. By the way you avoid many problems and long lined imports and don't care about where some_model lives among models/*.py files.
Thanks,
Sultan
BOOM!
I was using a different app_label for the new model but it has to be the same across the model group.
The other models labels were "mediocrelabel" and my new model had the label "coolabel". I changed the new model's label to "mediocrelabel" and now they are being added to the DB correctly.
Thanks for your help, folks!
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