Django not detecting changes in app model - python

I have created an app called base and added a new model to it. However, whenever I run python3 manage.py makemigrations base It says no changes detected.
I have already added my in installed apps
INSTALLED_APPS = [
...
'base.apps.BaseConfig',
...
]
And it does have the migrations folder inside the app containing and __init__.py file. I was wondering what is causing this issue.
This is my model:
from django.db import models
# Create your models here.
class BaseModel(models.Model):
created_at = models.DateTimeField(auto_now=True)
modified_at = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
And my settings contains 4 files:
settings:
--__init__.py
-- dev.py
-- prod.py
-- staging.py
-- common.py
My __init__.py:
import os
from .common import *
from decouple import config
environment = config('DEV_ENV', cast=str)
if environment == "dev":
from .dev import *
elif environment == "staging":
from .staging import *
elif environment == "prod":
from .prod import *
I have also already tried running
python3 manage.py makemigration base --settings=project.settings.dev and it still says
no changes detected

From the Abstract base classes doc,
Abstract base classes are useful when you want to put some common information into a number of other models. You write your base class and put abstract=True in the Meta class. This model will then not be used to create any database table. Instead, when it is used as a base class for other models, its fields will be added to those of the child class.
That is, if you remove abstract = True or set abstract = False, the Django will generate migration files for you!!!

Related

How to customize oscar address form fields?

after customizing django oscar app (address) and adding a new field named 'area' when I run migrate it gave me Unknown field(s) (area) specified for UserAddress
I used the command
./manage.py oscar_fork_app address myappsfolder/
after creating the folder and __init__.py file in it
then I started to customize the app like this:
#myappsfolder/address/models.py
from django.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from oscar.apps.address.abstract_models import AbstractAddress
class Address(AbstractAddress):
area = models.CharField(_("Area"), max_length=120,
choices=settings.AREA_CHOICES, blank=True)
from oscar.apps.address.models import *
#myappsfolder/address/forms.py
from oscar.apps.address import forms as base_forms
class UserAddressForm(base_forms.UserAddressForm):
class Meta(base_forms.UserAddressForm.Meta):
fields = ['area']
I didn't touch the admin.py , config.py and __init__.py that have been created by the command ./manage.py oscar_fork_app address myappsfolder/
also the __init__.py that I created in myappsfolder is empty, should I add something to these files ?
What should I do to customize this app ? or any other app ?
If I edited the models in oscar/apps/address/abstract_models.py it only apply in local host and the error in forms disappear , which means that django still reading the models from oscar/apps not from myappsfolder.
You cannot override AbstractAddress in that way because the changes will not propagate to other models such as UserAddress that directly subclass AbstractAddress. Instead you need to override the specific address models that you want to change. So if you want to change UserAddress then override that particular model:
from oscar.apps.address.abstract_models import AbstractUserAddress
class UserAddress(AbstractUserAddress):
area = models.CharField(_("Area"), max_length=120, choices=settings.AREA_CHOICES, blank=True)
... after which your changes to UserAddressForm should work.
If you need to override ShippingAddress as well, then you will also have to fork the shipping app and do the same thing there, because that is where the model lives.

Can we use apps.py for application-level configuration as a contrast to settings.py for project-level configurations?

This question has been asked earlier: What is the purpose of apps.py in Django 1.9?
Application configuration objects store metadata for an application. Some attributes can be configured in AppConfig subclasses. Others are set by Django and read-only.
However, what does it mean by metadata for application? Is it limited only to those AppConfig metadata:name, verbose_name, path, label, module, models_module?
Or does it make sense to extends beyonds the predefined metadata, especially for Application Specific metadata, for example in blog apps we have a date format configuration, usually defined as follows:
# File: settings.py
BLOG = {
'DATE_FORMAT': 'ddMMYYY',
}
At which it is being used as follow:
# File: blog/<...>.py
from django.conf import settings
date_format = settings.BLOG['DATE_FORMAT']
On contrary, we could move this configuration into blog/apps.py as BlogConfig?
class BlogConfig(AppConfig):
name = 'blog'
verbose_name = 'Awesome Blog'
date_format = 'ddMMYYYY'
So that throughout the code in the application, date_format is being used by:
# File: blog/<...>.py
from django.apps import apps
date_format = apps.get_app_config('blog').date_format
It sounds to me that settings.py is project settings, but not an application settings. Thus it is more sounds to put all application settings inside apps.py then settings.py. So, is this a valid assumption/argument/convention for me to put application configuration inside apps.py instead of settings.py?
A project is unique per django installation, while an app is supposed to be reusable.
If you put custom app settings in your project's settings.py they are supposed to be modifiable, especially if you (or others) reuse this app for another project.
Now, if you put these custom settings in your app's apps.py, this means they won't be modifiable on a per project basis. In which case there is no reason to put them in apps.py rather than in a constants submodule for instance. Unless you want to provide a limited set of possible configs:
class BlogConfig(AppConfig):
name = 'blog'
verbose_name = "Blog"
date_format = 'ddMMYYYY'
class CustomizableDateFormatBlogConfig(BlogConfig):
date_format = getattr(settings, 'BLOG_DATE_FORMAT', BlogConfig.date_format)
class I18nBlogConfig(BlogConfig)
verbose_name = _("Blog")
The default_app_config would be BlogConfig but the project using the app would be able to choose CustomizableDateFormatBlogConfig or I18nBlogConfig as well.
However this makes very poorly customizable apps. In the example above, if you want to let the app users use both CustomizableDateFormatBlogConfig and I18nBlogConfig, you would need to do something like this:
class BlogConfig(AppConfig):
name = 'blog'
verbose_name = "Blog"
date_format = 'ddMMYYYY'
class CustomizableDateFormatMixin:
date_format = getattr(settings, 'BLOG_DATE_FORMAT', BlogConfig.date_format)
class I18nMixin:
verbose_name = _("Blog")
class CustomizableDateFormatBlogConfig(CustomizableDateFormatMixin, BlogConfig):
pass
class I18nBlogConfig(I18nMixin, BlogConfig):
pass
class I18nCustomizableDateFormatBlogConfig(I18nMixin, CustomizableDateFormatMixin, BlogConfig):
pass
So, apart specific cases where you need to provide a set of few different app configs, you'd better put your custom app settings in the project's settings.py.

Models inside tests - Django 1.7 issue

I'm trying to port my project to use Django 1.7. Everything is fine except 1 thing. Models inside tests folders.
Django 1.7 new migrations run migrate command internally. Before syncdb was ran. That means if a model is not included in migrations - it won't be populated to DB (and also to test DB). That's exactly what I'm experiencing right now.
What I do is:
In my /app/tests/models.py I have dummy model: class TestBaseImage(BaseImage): pass
All it does is to inherit from an abstract BaseImage model.
Then in tests I create instances of that dummy model to test it.
The problem is that it doesn't work any more. It's not included in migrations (that's obvious as I don't want to keep my test models in a production DB). Running my tests causes DB error saying that table does not exist. That makes sense as it's not included in migrations.
Is there any way to make it work with new migrations system? I can't find a way to "fix" that.
Code I use:
app/tests/models.py
from ..models import BaseImage
class TestBaseImage(BaseImage):
"""Dummy model just to test BaseImage abstract class"""
pass
app/models.py
class BaseImage(models.Model):
# ... fields ...
class Meta:
abstract = True
factories:
class BaseImageFactory(factory.django.DjangoModelFactory):
"""Factory class for Vessel model"""
FACTORY_FOR = BaseImage
ABSTRACT_FACTORY = True
class PortImageFactory(BaseImageFactory):
FACTORY_FOR = PortImage
example test:
def get_model_field(model, field_name):
"""Returns field instance"""
return model._meta.get_field_by_name(field_name)[0]
def test_owner_field(self):
"""Tests owner field"""
field = get_model_field(BaseImage, "owner")
self.assertIsInstance(field, models.ForeignKey)
self.assertEqual(field.rel.to, get_user_model())
There is a ticket requesting a way to do test-only models here
As a workaround, you can decouple your tests.py and make it an app.
tests
|--migrations
|--__init__.py
|--models.py
|--tests.py
You will end up with something like this:
myapp
|-migrations
|-tests
|--migrations
|--__init__.py
|--models.py
|--tests.py
|-__init__.py
|-models.py
|-views.py
Then you should add it to your INSTALLED_APPS
INSTALLED_APPS = (
# ...
'myapp',
'myapp.tests',
)
You probably don't want to install myapp.tests in production, so you can keep separate settings files. Something like this:
INSTALLED_APPS = (
# ...
'myapp',
)
try:
from local_settings import *
except ImportError:
pass
Or better yet, create a test runner and install your tests there.
Last but not least, remember to run python manage.py makemigrations
Here's a workaround that seems to work. Trick the migration framework into thinking that there are no migrations for your app. In settings.py:
if 'test' in sys.argv:
# Only during unittests...
# myapp uses a test-only model, which won't be loaded if we only load
# our real migration files, so point to a nonexistent one, which will make
# the test runner fall back to 'syncdb' behavior.
MIGRATION_MODULES = {
'myapp': 'myapp.migrations_not_used_in_tests'
}
I found the idea on the first post in ths Django dev mailing list thread, and it's also currently being used in Django itself, but it may not work in future versions of Django where migrations are required and the "syncdb fallback" is removed.

When is django.conf.global_settings loaded?

I created following custom user model by using "AbstractUser" model.
from django.conf.global_settings import AUTH_USER_MODEL
MyCustomUser(AbstractUser):
regions = models.ManyToManyField(to='SomeModel')
class Meta:
app_label = 'myapp'
MyObject(models.Model):
owner = models.ForeignKey(to=AUTH_USER_MODEL)
And I set AUTH_USER_MODEL to settings/base.py (I separated setting file each environment. e.x: settings/base.py, settings/development.py).
AUTH_USER_MODEL = 'myapp.MyCustomUser'
When I executed python manage.py syncdb, my console window has flared up by Django!
myapp.MyObject: 'owner' defines a relation with the model 'auth.User', which has been swapped out. Update the relation to point at settings.AUTH_USER_MODEL.
So, I had two questions.
Is the problem is that I separated settings.py each environment.
Does from django.global_settings import AUTH_USER_MODEL import myproject.settings?
And I resolved from myproject.settings.base import AUTH_USER_MODEL in this time.
global_settings is, as the name implies, the global default settings supplied by Django. So of course the default is 'auth.User'.
Since you override it in your own settings, you should import that instead. But as the documentation says, the way to import the current settings is always from django.conf import settings, rather than explicitly importing a settings file in your project.
Also note though that rather than using the settings at all here - which could lead to some dependency issues on startup - you should be using get_user_model() from django.contrib.auth, as explained in the documentation.

Can i divide the models in different files in django

Currently all my models are in models.py. Ist becomming very messy.
Can i have the separate file like base_models.py so that i put my main models there which i don't want to touch
Also same case for views and put in separate folder rather than develop a new app
Yes, it's doable. It's not particularly pretty though:
make models a module, so your directory structure looks like this:
- models
|- __init__.py
|- some_model.py
|- some_other_model.py
|- ...
now, the magic lies in __init__.py and some little extras in the models. __init__.py:
from some_model import SomeModel
from some_other_model import SomeOtherModel
__all__ = [
'SomeModel',
'SomeOtherModel',
]
some_model.py:
class SomeModel(models.Model):
class Meta(object):
app_label = 'yourapplabel'
db_table = 'yourapplabel_somemodel'
Everything acjohnson55 said, plus the fact that you need to specify the app_label attribute in each model's Meta class.
A link to an actual example on github:
https://github.com/stefanfoulis/django-filer/tree/develop/filer/models
you can separate the model file like this :
-------models/
-------------- init.py
-------------- usermodels.py
--------------othermodel.py
in the init.py:
---------------from usermodels import *
---------------from othermodel import *
and in the *models.py , add META class:
--------class Meta:
--------------app_label = 'appName'
Yes, just make a folder called models and in that folder put all of your separated model files. You need to put a file called __init__.py in the models folder for it to be considered the models module. In __init__.py, use from ... import ... to put the names you want available directly in yourapp.models, otherwise you will have to import them as yourapp.models.base_model, or whatever submodule name you use.
Also, in each model, you will have to add a Meta attribute called app_label = 'yourapp' to make sure your models are recognized as part of the app.
This is how I normally do it:
# Folder structure:
#==================
# models/
# __init__.py
# products.py
# stocks.py
# In init.py (don't forget the period before model file name)
#===========
from .products import Product
from .stocks import Stock
__all__ = [
'Product',
'Stock',
]
# And run "py manage.py makemigrations" and "py manage.py migrate" as normal

Categories