Django - Import Models from an installed Package - python

I have all of my Django models in another package which I install using pip in a Django app.
models_package
| - models.py
| - setup.py
and in models.py i have
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
....
in my Django app i have
my_django_app
| ...
| models.py
website
| ...
| settings.py
manage.py
in my_django_app.model i have
from models_package.models import *
and in the website i have added my_django_app as an app (add it to INSTALLED_APP) and in website.settings.py i have
AUTH_USER_MODEL = "my_django_app.User"
but when i run python manage.py runserver i get:
RuntimeError: Model class my_django_app.models.User doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
The Thing is User which comes from models_packages.models and models_packages is not a Django app which I add to INSTALLED_APP in settings.py. it is only a package containing all shared Models that I need in multiple different Django apps.
Is there any way to use models in models_package.models without adding it to INSTALLED_APP inside website.settings.py

i think you need to transform your 'my_django_app' to a django app:
all you need to do is to add app.py inside my_django_app package
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'my_django_app'
then you can add it to your INSTALLED_APP

Related

Model not detected by Django, even with `app_label` referencing to an existing app

I have a Django project with an application called application.
The app is installed in the INSTALLED_APPS as follows:
### application/settings.py
INSTALLED_APPS = [
...
'application.apps.MyAppConfig',
]
with the AppConfig:
### application/apps.py
class MyAppConfig(AppConfig):
name = 'application'
verbose_name = 'My App'
label = 'application'
path = f"{os.environ.get('APP_DIR')}/application"
default = True
I have the models defined like this:
### data/models/basemodel.py
from django.db import models
class MyBaseModel(models.Model):
# ... fields ...
Meta:
app_label: `application`
Project's tree:
main_dir/
data/
__init__.py
models/
__init__.py
basemodel.py
application/
__init__.py
apps.py
urls.py
settings.py
...
Django is not finding the models, and if I run makemigrations Django responds No changes detected, and on migrate, the app application does not appear on the Operations to perform.
I want to split the data layer from the logic and interface layers. In order to do so, I've the models and other data-related business inside data (outside any installed app)
The goal is to link the models to the app from there, without having to declare any model inside the application dir.
The Model should be detected so the Django detects migrations to apply.
Context:
Django Application reference: doc
Django Models reference: doc
I guess you want to have a single module per model ? If so, you need to import your models inside models\__init__ like so:
from .basemodel import BaseModel
I also suggest that you define __all__ inside your init file, in order to import your models easily in other parts of the app:
__all__ = ["BaseModel"]
from .basemodel import BaseModel

Django app dissapears from Django Admin site when I add apps.py file

I'm working with Django 3.2 and trying to configure correctly the AppsConfig subclass of apps.py in order to avoid duplicate apps names when initzialing the project.
The context is the following. I have in my INSTALLED_APPS two apps whose names are equal although their paths not:
INSTALLED_APPS = [
...
'first_app.myapp',
'second_app.myapp'
]
To avoid the error shown below (and according to the documentation), I need to create an apps.py file subclassing AppConfig in at least one of the apps called myapp. I've decided to create that file in the second one, second_app.myapp.
django.core.exceptions.ImproperlyConfigured: Application labels aren't unique, duplicates: myapp
The app.py in second_app.myapp module looks like as follows:
from django.apps import AppConfig
class MySecondAppConfig(AppConfig):
name = "second_app.myapp"
label = "my_second_app"
And in the __init__.py I've added:
default_app_config = 'second_app.myapp.apps.MySecondAppConfig'
My admin.py looks like:
from django.contrib import admin
from .models import MyModel
class MySecondAppAdminModel(admin.ModelAdmin):
list_display = ('attr_1', 'attr_2')
admin.site.register(MyModel, MySecondAppAdminModel)
When I start the project all works OK and I can use that model information, views called from second_app.myapp also work OK.
The problem comes when I access to the admin site (http://localhost:8000/admin), where only appears the first_app.myapp admin form instead of both.
Can you help me? Thanks in advance.
instead of this:
INSTALLED_APPS = [
...
'first_app.myapp',
'second_app.myapp'
]
Just try this way only:
INSTALLED_APPS = [
...
'first_app',
'second_app'
]
You got that error because here first_app.myapp and second_app.myapp myapp is duplicate. you should not use like this in both the apps.
OR
INSTALLED_APPS = [
...
'first_app.apps.MyFirstAppConfig',
'second_app.apps.MySecondAppConfig'
]

Django-ajax-selects with AJAX_SELECT_BOOTSTRAP = False

At work we are using django-admin webapp. I wanted to implement django-ajax-selects functionality to some of fields. Our network is isolated from Internet and I cannot use django-ajax-selects's CDNs. Documentation says that in such case you should set AJAX_SELECT_BOOTSTRAP to False in settings.py file. However, when I set this parameter, django-ajax-selects fails to use django's jquery.
Django's version is 1.11.10, Python2.
Steps to reproduce my issue:
pip install django==1.11.10 django-ajax-selects
django-admin startproject proj ./
python manage.py startapp test_app
python manage.py migrate
python manage.py createsuperuser
test_app/models.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=100)
something = models.CharField(max_length=100)
def __str__(self):
return self.name
class SecondModel(models.Model):
name = models.CharField(max_length=200)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
def __str__(self):
return self.name
test_app/lookups.py
from ajax_select import register, LookupChannel
from .models import Tag
#register('tags')
class TagsLookup(LookupChannel):
model = Tag
def get_query(self, q, request):
return self.model.objects.filter(name__icontains=q)
def format_item_display(self, item):
return u"<span class='tag'>%s</span>" % item.name
test_app/admin.py
# -*- coding: utf-8 -*-
from django.contrib import admin
from ajax_select import make_ajax_form
from .models import Tag, SecondModel
#admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
fields = ['name', 'something']
#admin.register(SecondModel)
class SecondModelAdmin(admin.ModelAdmin):
form = make_ajax_form(SecondModel, {
'tag': 'tags'
})
proj/settings.py - adding the app and ajax_select to INSTALLED_APPS
INSTALLED_APPS = (
...
'ajax_select',
'test_app',
)
proj/urls.py
from django.conf.urls import url, include
from django.contrib import admin
from ajax_select import urls as ajax_select_urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^ajax_select/', include(ajax_select_urls)),
]
Then
python manage.py makemigrations test_app
python manage.py migrate
If I run the server like that it works absolutely fine (because it uses CDNs to load jquery and stuff).
But if I set AJAX_SELECT_BOOTSTRAP to False I will get a TypeError in browser's console and the ajax functionality will not work. I guess ajax_select.js just loads before django's jquery was loaded. I could not figure it out, how can I specify load order or may be there is another way? Template overriding would be not very good idea as there is some overriding already used by other apps and I'm afraid it can cause some conflicts.
In the end what I needed to do was to manually download jquery.min.js, jquery-ui.js, jquery-ui.css and also jquery-ui images library, put them into app's static directory and point to them in admin.py:
admin.py
...
#admin.register(SecondModel)
class SecondModelAdmin(admin.ModelAdmin):
form = SecondModelForm
class Media:
js = ["/static/js/jquery.min.js",
"/static/js/jquery-ui.js"]
css = {'all': ["/static/css/jquery-ui.css"]}
Also don't forget to run python manage.py collectstatic for static files to be copied to common static directory.

Models and inheritance

Stumbled upon something very weird today.
I created a minimal project/application that can show the issue. This is how I did it:
virtualenv venv
. ./ven/bin/activate
pip install django==1.6 # That's the one we're using
django-admin.py startproject bla
cd bla
chmod +x manage.py
./manage.py startapp bla_app
in bla/settings.py:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bla_app',
)
AUTH_USER_MODEL = 'bla_app.MyUser'
in bla_app/models.py:
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class MyUser(AbstractUser):
super_name = models.CharField(max_length=254, unique=True)
Then, I run the syncdb command:
./manage.py syncdb
And it's been created as expected.
Now comes the tricky part. If I replace the models.py with a folder called models, and create an __init__.py file containing:
from my_user import MyUser
(the previous models.py was moved into models/ as my_user.py)
I then get these errors:
$ ./manage.py syncdb
CommandError: One or more models did not validate:
admin.logentry: 'user' has a relation with model bla_app.MyUser, which has either not been installed or is abstract.
auth.user: Model has been swapped out for 'bla_app.MyUser' which has not been installed or is abstract.
Do you have an idea of what is going on here?
I found that, but I'm not sure they're related
Django expects your model classes to be defined in models.py itself, not in a submodule. It's going to try to create an instance of models.MyUser which in your case does not exist in Django's world even though you've defined it in my_user.py
If you're looking to define each model in a separate Python file, you'd need to create a models.py file that imports them manually. This will likely be hard to maintain if you start creating a lot of models in that app.
app/
__init__.py
models.py
_models/
__init__.py
my_user.py
In models.py
from ._models.my_user import MyUser
To split your model into modules, you have to provide the app_label Meta Option. Ex:
my_user.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
super_name = models.CharField(max_length=254, unique=True)
class Meta:
app_label = 'bla_app'
As #petkostas said, it will not be required in Django 1.7 (issue 4470)
Take a look at this answer, which describes the process.

Custom User model in Python with socialaccount

I would like to create a User model that has an additional couple fields in django. I tried to do so by following the advice
https://stackoverflow.com/a/22696794/3426600 to create a custom user model
in models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
user_data = models.TextField(null=True)
In settings.py
AUTH_USER_MODEL = 'app_name.User'
but when I run python manage.py syncdb
I get the errors:
CommandError: One or more models did not validate:
account.emailaddress: 'user' has a relation with model app_name.User, which has either not been installed or is abstract.
admin.logentry: 'user' has a relation with model app_name.User, which has either not been installed or is abstract.
auth.user: Model has been swapped out for 'app_name.User' which has not been installed or is abstract.
socialaccount.socialaccount: 'user' has a relation with model app_name.User, which has either not been installed or is abstract.
Could I be using the wrong app_name? If so, where do I find the app_name?
How do I make the custom user work with socialaccount, etc?
Assume your project strucutre is something like below, and the codes of User(AbstractUser) are located in mysite/mysite/app1/models.py:
mysite/ (root folder for the project, put it anywhere in your disk. Most developers have a workspace folder(s) in computer)
(other non-application things. E.g. a static/, README.md, ...)
manage.py
mysite/ (container for all applications. You can put applications directly under root folder, but not recommended)
__init__.py
settings.py
urls.py
wsgi.py
app1/ (each application resides in its own folder. You don't want to put all models in one models.py file or all views in one view.py file, right?)
__init__.py
models.py
views.py
......
Then the app_name is app1, i.e. AUTH_USER_MODEL = 'app1.User'. Meanwhile, you need to add mysite.app1 into INSTALLED_APPS in settings.py. This probably will solve you CommandError issue.
ADDED NOTES:
Each application, you can consider it as a module of your project. The app_name of the application is the folder name. If you have defined models in one application, must add it into INSTALLED_APPS in settings.py.
Manually creating a folder is not a good way. django-admin.py startapp is more recommended, because it together creates some common files for an application, e.g. init.py, models.py, view.py, ...
Suggest you to go through the django quick-start guide, if you haven't done it: https://docs.djangoproject.com/en/dev/intro/tutorial01/

Categories

Resources