How to additional field to Django Oscar Order model? - django

I want add additional field to Order model. i have already forked order app.
below is the code added in Order model in forked_app Order app.
from django.utils import timezone
from oscar.apps.order.abstract_models import AbstractOrder
from oscar.apps.order.models import * # noqa isort:skip
from django.db import models
class Order(AbstractOrder):
status_update_time = models.CharField(max_length=30)
def save(self, *args, **kwargs):
self.status_update_time = timezone.now()
super(Order, self).save(*args, **kwargs)
Below is the error i get while migrations.
class Order(AbstractOrder):
NameError: name 'AbstractOrder' is not defined
Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0x7f06737e6d08>
RuntimeError: Conflicting 'order' models in application 'order': <class 'oscar.apps.order.models.Order'> and <class 'forked_apps.order.models.Order'>.

from django.utils import timezone
from oscar.apps.order.abstract_models import AbstractOrder
from django.db import models
class Order(AbstractOrder):
status_update_time = models.CharField(max_length=30)
def save(self, *args, **kwargs):
self.status_update_time = timezone.now()
super(Order, self).save(*args, **kwargs)
at the end of the models.py file
from oscar.apps.order.models import *
then try to do makemigrations and then migrate

In order to customize models, views and urls, you need to fork an Oscar core app in which model/view resides. Then you should be able to override any model/view classes.
Steps to fork/customize an app:
If you are forking an Oscar app for the first time, then you have to create a root apps-folder in which all your forked apps will exists:
$ mkdir yourappsfolder
$ touch yourappsfolder/init.py
Create a python module with the same ‘app-label’ as the Oscar app:
Ex: Customising oscar.apps.catalogue app
$ mkdir yourappsfolder/catalogue
$ touch yourappsfolder/catalogue/__init__.py
If the Oscar app has a models.py, then you have to create a models.py file in your local app.
your custom models go here
from oscar.apps.catalogue.models import *
NOTE: To customise Oscar’s models, you must add your custom one before importing Oscar’s models. Then, your models file will have two models with the same name within an app, Django will only use the first one.
Ex: To add a active field to the product model:
# yourappsfolder/catalogue/models.py
from django.db import models
from oscar.apps.catalogue.abstract_models import AbstractProduct
class Product(AbstractProduct):
active = models.BooleanField(default=False)
from oscar.apps.catalogue.models import *
Create an ‘admin.py’ file in your local app.
yourappsfolder/catalogue/admin.py
from oscar.apps.catalogue.admin import *
Then copy the ‘migrations’ directory from oscar/apps/catalogue and put it into your new local catalogue app.
Added it as Django app by replacing Oscar’s app with your own in INSTALLED_APPS.
settings.py
from oscar import get_core_apps
INSTALLED_APPS = [
...,
# all your non-Oscar apps
] + get_core_apps(['yourappsfolder.catalogue'])
NOTE: get_core_apps([]) will return a list of Oscar core apps or else if you give a list of your custom apps, they will replace the Oscar core apps.
Finally, create migrations using ‘makemigrations’ management command and apply the migrations by using ‘migrate catalogue’ management command. Then, you can see that a new column is been added to the product model.

Related

Not able to save data from admin site in django app

I am building an app in django to keep track of social events. I am trying to handle recurring events through django-simple-events package. Issue is when I try to save any data from the admin site, it says record successfully added but when I check my model I don't see any record. When I click the object from recent activity I get an error 404 with the following message study object with primary key u'None' does not exist.
models.py
from django.db import models
from django.contrib.contenttypes import generic
from events.models import Event
class Study(models.Model):
study_event_name = models.CharField(max_length=140)
events = generic.GenericRelation(Event)
location = models.CharField(max_length=140)
def save(self):
super(Study, self).save
def __unicode__(self):
return self.study_event_name
admin.py
from django.contrib import admin
from study.models import Study
from events.admin import EventInline
# Register your models here.
class StudyAdmin(admin.ModelAdmin):
inlines = EventInline,
admin.site.register(Study, StudyAdmin)
Can anyone help me in figuring out what I am doing wrong here.

Django: AttributeError: type object 'MyAppConfig' has no attribute 'rpartition'

I am trying to add view_amodel permission to my models. I decided to add the permission after migration. So I made following approach.
At an_app/init.py
from an_app.apps import MyAppConfig
default_app_config = MyAppConfig
At an_app/apps.py
from django.apps import AppConfig
from django.db.models.signals import post_migrate
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Permission
def add_view_permissions(sender, **kwargs):
"""
This syncdb hooks takes care of adding a view permission too all our
content types.
"""
# for each of our content types
for content_type in ContentType.objects.all():
# build our permission slug
codename = "view_%s" % content_type.model
# if it doesn't exist..
if not Permission.objects.filter(content_type=content_type, codename=codename):
# add it
Permission.objects.create(content_type=content_type,
codename=codename,
name="Can view %s" % content_type.name)
print "Added view permission for %s" % content_type.name
class MyAppConfig(AppConfig):
def ready(self):
post_migrate.connect(add_view_permissions, sender=self)
When I do python manage.py migrate, I get following error,
AttributeError: type object 'MyAppConfig' has no attribute 'rpartition'
How to solve it.
The reference to the AppConfig in the app's __init__.py is supposed to be a string, not the class itself.
Specify
default_app_config = 'an_app.apps.MyAppConfig'
and remove the import.
See the documentation.

Django admin - how to get all registered models in templatetag?

I'm writing a custom admin stuff and need to get all registered models in Admin. Is this possible? I need it to make some custom views on admin index page.
You can access admin.site._registry dict of Model->ModelAdmin:
>>> ./manage.py shell
In [1]: from urls import * # load admin
In [2]: from django.contrib import admin
In [3]: admin.site._registry
Out[3]:
{django.contrib.auth.models.Group: <django.contrib.auth.admin.GroupAdmin at 0x22629d0>,
django.contrib.auth.models.User: <django.contrib.auth.admin.UserAdmin at 0x2262a10>,
django.contrib.sites.models.Site: <django.contrib.sites.admin.SiteAdmin at 0x2262c90>,
testapp.models.Up: <django.contrib.admin.options.ModelAdmin at 0x2269c10>,
nashvegas.models.Migration: <nashvegas.admin.MigrationAdmin at 0x2262ad0>}
This is what the admin index view does:
#never_cache
def index(self, request, extra_context=None):
"""
Displays the main admin index page, which lists all of the installed
apps that have been registered in this site.
"""
app_dict = {}
user = request.user
for model, model_admin in self._registry.items():
# ...
Note that variables prefixed with an underscore are potentially subject to changes in future versions of django.
You can do something like this:
from django.apps import apps
models = apps.get_models()
for model in models:
try:
my_custom_admin_site.register(model)
except admin.sites.AlreadyRegistered:
pass
apps.get_models() will give all the registered models in the default Django Admin site.

Register every table/class from an app in the Django admin page

I have an app named doors and my models.py for the app has 10 tables/class. Under my admin.py, how do I register every model in the file models.py?
For example, currently I have to hardcode it:
from django.contrib import admin
from doors.models import *
admin.site.register(Group)
admin.site.register(Item)
admin.site.register(ItemType)
admin.site.register(Location)
admin.site.register(Log)
admin.site.register(Order)
admin.site.register(Property)
admin.site.register(User)
admin.site.register(Vendor)
Is there a way I perhaps find every class in models.py and loop through and register each class? Or is there some kind of wildcard I can use with Django?
Seems get_models and get_app are no longer available in django 1.8.
The following can be used:
from django.contrib import admin
from django.apps import apps
app = apps.get_app_config('dashboard')
for model_name, model in app.models.items():
admin.site.register(model)
EXTENSION: If you would like to show all or select fields of the model as a grid instead of a single column unicode representation of the model objects you may use this:
app = apps.get_app_config('your_app_name')
for model_name, model in app.models.items():
model_admin = type(model_name + "Admin", (admin.ModelAdmin,), {})
model_admin.list_display = model.admin_list_display if hasattr(model, 'admin_list_display') else tuple([field.name for field in model._meta.fields])
model_admin.list_filter = model.admin_list_filter if hasattr(model, 'admin_list_filter') else model_admin.list_display
model_admin.list_display_links = model.admin_list_display_links if hasattr(model, 'admin_list_display_links') else ()
model_admin.list_editable = model.admin_list_editable if hasattr(model, 'admin_list_editable') else ()
model_admin.search_fields = model.admin_search_fields if hasattr(model, 'admin_search_fields') else ()
admin.site.register(model, model_admin)
What this does is, it extends ModelAdmin class on the fly and sets the list_display field which is required for showing model data in grid representation in the admin. If you list your desired fields in your model as admin_list_display it takes that one, or generates a tuple of all fields available in the model, otherwise.
Other optional fields can similarly be set, such as list_filter.
See django documentation for more info on list_display.
I figured it out with #arie's link (for django < 1.8):
from django.contrib import admin
from django.db.models import get_models, get_app
for model in get_models(get_app('doors')):
admin.site.register(model)
But I wonder if I can do this without get_app... Couldn't the code be smart enough to know the name of its own app?
From Django 1.7 on, you can use this code in your admin.py:
from django.apps import apps
from django.contrib import admin
from django.contrib.admin.sites import AlreadyRegistered
app_models = apps.get_app_config('my_app').get_models()
for model in app_models:
try:
admin.site.register(model)
except AlreadyRegistered:
pass
From Django 1.8, to fix the error message
RemovedInDjango19Warning: django.db.models.get_app is deprecated.
We can use this approach in 2 lines
from django.contrib import admin
from my_app.models import *
from django.apps import apps
for model in apps.get_app_config('my_app').models.values():
admin.site.register(model)
from django.apps import apps
from django.contrib.admin.sites import AlreadyRegistered
app_models = apps.get_app_config('app-name').get_models()
for model in app_models:
try:
admin.site.register(model)
except AlreadyRegistered:
pass
from django.contrib import admin
from .models import Projects, ProjectsUsers, Comments, ProjectsDescription
Models = (Projects, ProjectsUsers, Comments, ProjectsDescription)
admin.site.register(Models)
From Django3.0,you can try add the following code in admin.py
from . import models
class ListAdminMixin(object):
def __init__(self, model, admin_site):
self.list_display = [field.name for field in model._meta.fields if field.name != "id"]
super(ListAdminMixin, self).__init__(model, admin_site)
for m in [your_model_name]:
mod = getattr(models, m)
admin_class = type('AdminClass', (ListAdminMixin, admin.ModelAdmin), {})
try:
admin.site.register(mod, admin_class)
except admin.sites.AlreadyRegistered:
pass

Django : How can I find a list of models that the ORM knows?

In Django, is there a place I can get a list of or look up the models that the ORM knows about?
Simple solution:
import django.apps
django.apps.apps.get_models()
By default apps.get_models() don't include
auto-created models for many-to-many relations without
an explicit intermediate table
models that have been swapped out.
If you want to include these as well,
django.apps.apps.get_models(include_auto_created=True, include_swapped=True)
Prior to Django 1.7, instead use:
from django.db import models
models.get_models(include_auto_created=True)
The include_auto_created parameter ensures that through tables implicitly created by ManyToManyFields will be retrieved as well.
List models using http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
from django.contrib.contenttypes.models import ContentType
for ct in ContentType.objects.all():
m = ct.model_class()
print "%s.%s\t%d" % (m.__module__, m.__name__, m._default_manager.count())
If you want a dictionary with all models you can use:
from django.apps import apps
models = {
model.__name__: model for model in apps.get_models()
}
If you want to play, and not use the good solution, you can play a bit with python introspection:
import settings
from django.db import models
for app in settings.INSTALLED_APPS:
models_name = app + ".models"
try:
models_module = __import__(models_name, fromlist=["models"])
attributes = dir(models_module)
for attr in attributes:
try:
attrib = models_module.__getattribute__(attr)
if issubclass(attrib, models.Model) and attrib.__module__== models_name:
print "%s.%s" % (models_name, attr)
except TypeError, e:
pass
except ImportError, e:
pass
Note: this is quite a rough piece of code; it will assume that all models are defined in "models.py" and that they inherit from django.db.models.Model.
If you use the contenttypes app, then it is straightforward: http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
If you register your models with the admin app, you can see all the attributes of these classes in the admin documentation.
Here's a simple way to find and delete any permissions that exist in the database but don't exist in the ORM model definitions:
from django.apps import apps
from django.contrib.auth.management import _get_all_permissions
from django.contrib.auth.models import Permission
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def handle(self, *args, **options):
builtins = []
for klass in apps.get_models():
for perm in _get_all_permissions(klass._meta):
builtins.append(perm[0])
builtins = set(builtins)
permissions = set(Permission.objects.all().values_list('codename', flat=True))
to_remove = permissions - builtins
res = Permission.objects.filter(codename__in=to_remove).delete()
self.stdout.write('Deleted records: ' + str(res))