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.
Related
I am using oscarcommerce for my django project. I want to extend the "StockRecord" model to include some more fields. So I forked the partner app as follows. (boscar is my app name)
python manage.py oscar_fork_app partner boscar/
It successfully forked and new files were added to boscar/partner folder. I added 'boscar.partner' in my installed apps.
Now I added new fields in StockRecord models as follows
boscar/partner/models.py
from django.db import models
from oscar.apps.partner.abstract_models import AbstractStockRecord
class StockRecord(AbstractStockRecord):
effective_price = models.FloatField(default=0, null=True)
is_instock_item = models.BooleanField(default=False, null=True)
instock_quantity = models.IntegerField()
from oscar.apps.partner.models import * # noqa
Now when I try to make migrations it shows the following error.
RuntimeError: Conflicting 'stockrecord' models in application 'partner': <class 'oscar.apps.partner.models.StockRecord'> and <class 'boscar.partner.models.StockRecord'>.
I already successfully forked the catalogue and order models and that are working fine. Only this "StockRecord" models showing this error.
That error can occur as a result of a circular import issue associated with Oscar's support for overriding models and classes.
You need to check for places where you're importing directly from oscar.apps.partner.models. These should be replaced by importing from boscar.partner.models or using oscar.core.loading.get_model.
I have two Django models.py in two different apps.
processor app models.py
from address.models import Address
...defining clasess
class Displayble(models.Model):
# It has no DB fields
address app models.py
from processor.models import Displayable
class Address(models.Model, Displayble):
...some fields, stored in DB
Is moving Dispalyble class to another file is the only option to resolve this dependency?
Import the Address model with django's apps.get_model. https://docs.djangoproject.com/en/1.11/ref/applications/#django.apps.apps.get_model.
In your processor app models.py replace
from address.models import Address
...defining clasess
class Displayble(models.Model):
# It has no DB fields
With
from django.apps import apps
Address = apps.get_model(app_label='address', model_name='Address')
....go ahead and use Address as though imported
class Displayable(models.Model):
...
I've made a django app, which is designed to be easily pluggable, and only has 1 view, and 1 model that project planning to use the app need to be aware of.
For ease, I'd like to just make the view and model available from the app-level. So rather than:
from mything.views import MyView
from mything.models import MyModel
You can instead just do:
from mything import MyView, MyModel
I changed the __init__.py file in the app to be like this:
from .views import MyView
from .models import MyModel
Of course I get the old django.core.exceptions.AppRegistryNotReady raised, since it's attempting to run the models.py code before the apps are loaded.
So I came up with the following workaround, and I'm wondering if it's a reasonable pattern to use or not. Now in __init__.py I have:
def _expose_items():
from .views import MyView
from .models import MyModel
globals()['MyView'] = MyView
globals()['MyModel'] = MyModel
And in my app's apps.py:
from . import _expose_items
class MyThingConfig(AppConfig):
name = 'mything'
def ready(self):
_expose_items()
So now indeed, I can directly import the view and model from the outside. Is this useful, or horrible?
Most Django apps do not collect views or models to the top level module. Refer to django.contrib.auth as an example.
Most Django apps do not collect views or models to the top level module. Use clear documentation to demonstrate how to import from your app. Hacks including globals() will probably create more trouble than help.
Refer to django.contrib.auth as an example.
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.
in my new Django app I use 3rd-part Photologue app.
This app works well, but I need to add some field in its model without change the original source code of Photologue app.
With this snippet, all works well, but maybe this is not the best solution:
Photo.add_to_class("link", models.URLField(max_leng.... ))
I've read some posts where I should use OneToOneRelationField ... but then, in django admin app, I will have two different form page of Photo and new PhotoLink class...
Does anyone can help me?
If you are using a OneToOneField, you can use your 'extension' model as an inline to the model you are extending. You do this by first un-registering the original admin class, and then overriding it with our variant:
from otherapp.admin import OriginalFooAdmin
from otherapp.models import Foo
from yourapp.models import YourExtension
from django.contrib import admin
admin.site.unregister(Foo)
class ExtensionInline(admin.StackedInline):
model = YourExtension
class NewFooAdmin(OriginalFooAdmin):
inlines = OriginalFooAdmin.inlines + [ExtensionInline]
admin.site.register(Foo, NewFooAdmin)