Conflicting models when overriding - django

It seems like oscar is not picking up my pointed local folder.
INSTALLED_APP = [] + get_core_apps(['myoscar.partner'])
My error is
Conflicting 'partner' models in application 'partner': <class "oscar.app.partner.models.Partner"> and <class "myoscar.partner.models.Partner">
This also leads me to another related question - there's two settings.py. I've tried adding in both. When I remove myoscar.partner in my main app, I obviously dont get the error but it gives me oscar's default model - which makes sense but then I run into the above error when I add it in. I don't know of anywhere else I'm registering the partner model before this override - at least not that I know of.
My question is
1) which settings.py is the right one? I want to make sure.
2) why do I get this error when I pointed to the forked folder? Is it not picking up my folder?
App/myoscar/partner/models.py
from django.contrib.auth import get_user_model
from django.db import models
from oscar.apps.partner.abstract_models import AbstractPartner
User = get_user_model()
class Partner(AbstractPartner):
users = models.OneToOneField(User,related_name='partner_user')
from oscar.apps.partner.models import *
#per some answers on stackoverflow, I've also tried removing this but the docs say this should be added here to keep the other models.
my folder structure:
App
|--app
|----__init.py__
|----settings.py
|----urls.py
|--myoscar
|----partner
|-------models.py
|----myoscar
|------settings.py
|------urls.py
|--mysub
|----migrations

The problem seems with related_name value. Try using a different value for it.

Related

Use model from the versioned app registry globally

I'd like to run a custom command in my migration, that calls functions from other modules. These functions use some models, and as expected I ran into schema version mismatch (OperationalError: (1054, "Unknown column 'foo' in 'bar'").
If I were to use those models in the custom command I'd access the model with apps.get_model('my_app', 'bar'), but as those models are used in the external functions, I can't do that.
I'm sure, someone ran into this before although I couldn't find anything.
I was thinking about using the unittest.mock.patch decorator but it doesn't feel like the right solution.
I'm wondering if there's a more general solution for this?
The versioned app registries are not globally accessible. You could pass the model as a parameter to the function, and use the current model as the default:
from my_app.models import Bar
def my_function(..., bar_model=Bar):
# Use bar_model instead of Bar
# Your RunPython function
def migrate_something(apps, schema_editor):
my_function(bar_model=apps.get_model('my_app', 'bar'))
You don't have to pass the bar_model parameter if you call it from regular code, but when calling it from a migration you can pass the historical model.
If you need multiple models you could pass apps instead:
from django.apps import apps as global_apps
def my_function(..., apps=global_apps):
Bar = apps.get_model('my_app', 'bar')

get_model() vs from .models import somemodelname

What is/are the best practices to use get_model() and when should it be imported ?
Ref: https://docs.djangoproject.com/en/1.8/ref/applications/
You usually use get_model() when you need to dynamically get a model class.
A practical example: when writing a RunPython operation for a migration, you get the app registry as one of the args, and you use apps.get_model('TheModel') to import historical models.
Another example: you have an app which has dynamically built serializers and you set their Meta.model to the class you just got with get_model() .
Yet another example is importing models in AppConfig.ready() with self.get_model().
An important thing to remember, if you are using AppConfig.get_model() or apps.get_models(), that they can be used only once the application registry is fully populated.
The other option (from .models import TheModel) is just the default way to import models anywhere in your code.
These are just examples though, there are many other possible scenarios.
I Prefer, use .models import, cause is a simple way to get the Model Object.
But if you works with metaclasses, maybe the get_model, would be the best option.
def get_model(self, app_label, model_name=None):
"""
Returns the model matching the given app_label and model_name.
As a shortcut, this function also accepts a single argument in the
form <app_label>.<model_name>.
model_name is case-insensitive.
Raises LookupError if no application exists with this label, or no
model exists with this name in the application. Raises ValueError if
called with a single argument that doesn't contain exactly one dot.
"""
self.check_models_ready()
if model_name is None:
app_label, model_name = app_label.split('.')
return self.get_app_config(app_label).get_model(model_name.lower())
Maybe this SO POST, can help too.

Django - Foreign key to another app with a complex name

I'm writing a Django Model that will link to another app Model. I know that we should link the ForeginKeys with "nameoftheapp.nameofthemodel" but I'm not successful doing it with this use case.
Here is my installed_apps:
INSTALLED_APPS = (
...
'signup',
'paypal.standard.ipn',
...
)
Basically I'm creating a model in the app "signup" and I need to do a foreignkey to "paypal.standard.ipn".
Here is my model:
class SignupPaymentPayPal(models.Model):
gettingstarted = models.ForeignKey('GettingStarted')
paypalipn = models.ForeignKey('paypal.standard.ipn.PayPalIPN')
The model I need to link is this one, https://github.com/spookylukey/django-paypal/blob/master/paypal/standard/ipn/models.py
When I try to do a shemamigration I got this:
$ python manage.py schemamigration signup --auto
Here is the error I got:
CommandError: One or more models did not validate:
signup.signuppaymentpaypal: 'paypalipn' has a relation with model paypal.standard.ipn.PayPalIPN, which has either not been installed or is abstract.
Any clues on what I'm doing wrong?
Best Regards,
from paypal.standard.ipn.models import PayPalIPN
class SignupPaymentPayPal(models.Model):
gettingstarted = models.ForeignKey('GettingStarted')
paypalipn = models.ForeignKey(PayPalIPN)
André solution works, and in fact I'd recommend using the actual model instead of a string whenever possible, to avoid any unexpected errors when the string can't be resolved to a model, but here's an explanation why your previous method didn't work:
Django has a model cache that keeps track of all Model subclasses that are created. Each model is uniquely identified by an appname and modelname, but not by a fully qualified import path.
Let's say I have two models, one is myapp.reviews.Review, the other is myapp.jobs.reviews.Review. If myapp.reviews.Review comes first in my INSTALLED_APPS, both classes will actually be the myapp.reviews.Review model:
>>> from myapp.jobs.reviews import Review
>>> Review
<class 'myapp.reviews.Review'>
To specify a ForeignKey using a string instead of a class (e.g. to avoid circular imports), you need to follow the '<appname>.<modelname>' format, i.e.:
class SignupPaymentPayPal(models.Model):
paypalipn = models.ForeignKey('ipn.PayPalIPN')

django-nonrel: add element in LisftField of ForeignKeys

I'm trying to implement a list of foreignKeys in django-nonrel (I'm using mongo as db).
Here is the code:
# models.py
from django.db import models
from django_mongodb_engine.contrib import MongoDBManager
from djangotoolbox.fields import ListField
class FriendList(models.Model):
objects = MongoDBManager()
list = ListField(models.ForeignKey('AWUser'))
def add_friend(self, awuser):
# awuser must be an instance of AWUser - I removed tests for more clarity
self.list.append(awuser)
self.save()
class AWUser(models.Model):
objects = CustomUserManager()
user = EmbeddedModelField('User')
friends = EmbeddedModelField('FriendList')
The problem is that when I call user.friends.add_friend(user1), I have the error "AttributeError: 'str' object has no attribute '_meta'".
Breaking example (made using ./manage shell console):
$>user = AWUser.objects.all()[0]
$>user1 = AWUser.objects.all()[1]
$>user.friends.add_friend(user1)
#ask me if you need the complete error - I don't put it more more clarity
AttributeError: 'str' object has no attribute '_meta'
What I basically need is to create friend lists.
Please feel free to recommend a different implementation if you think mine is not good. :) I would love to have my implementation working though...
Also, I did not put all the variables of AWUser for more clarity but I can add them if necessary.
Related project dependencies:
django 1.3.1 (installed as django-nonrel)
django-mongodb-engine 0.4.0
djangotoolbox==0.9.2
List item
pymongo==2.1.1
Thanks for your help.
UPDATE:
I tried to change the code as said in the post "ListField with ForeignField in django-nonrel" but I still have the same error...
According to the Django MongoDB Engine documentation, it suggests to use EmbeddedModel from djangotoolbox:
from djangotoolbox.fields import ListField, EmbeddedModelField
class Post(models.Model):
...
comments = ListField(EmbeddedModelField('Comment'))
class Comment(models.Model):
text = models.TextField()
Edit: Forgot the link: http://django-mongodb-engine.readthedocs.org/en/latest/topics/embedded-models.html
I actually just figured out what was wrong.
It is apparently impossible to declare the foreign key class type as a string when in a Listfield. Weird...
If it happens to you, just do the following change:
list = ListField(models.ForeignKey('AWUser'))
becomes:
list = ListField(models.ForeignKey(AWUser))
If anyone as a good explanation of what is going on, I'd love to hear it :)

django: how to extend an existing model

there are plenty of examples the tell you how to extend the user model BUT I cannot find a real, complete and documented example on how to extend an existing model without having to follow the "user profile pattern" (and honestly I wonder why).
In short, my use case is the following: I need to extend django-lfs's product model.
In LFS is registered like this (in lfs.catalog.admin):
from django.contrib import admin
[...]
from lfs.catalog.models import Product
[...]
class ProductAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("name", )}
admin.site.register(Product, ProductAdmin)
[...]
I tried to register mine (that subclasses it) but I got:
django/contrib/admin/sites.py",
line 78, in register
raise AlreadyRegistered('The model %s is already registered' %
model.name)
So, someone suggested me that I have to unregister that object and register mine.
I did it like this:
from lfs.catalog.models import Product
from lfs.catalog.admin import ProductAdmin
admin.site.unregister(Product)
from lfs_product_highlights.catalog.models import Product
admin.site.register(Product,ProductAdmin)
No errors this time BUT there's no change, my custom fields are nowhere to be seen.
Any hints?
The reason why it's difficult is because of the object-relational impedance mismatch (love that phrase). Objects and classes do not map perfectly onto relational databases: ORMs like Django's attempt to smooth out the edges, but there are some places where the differences are just too great. Inheritance is one of these: there is simply no way to make one table "inherit" from another, so it has to be simulated via Foreign Keys or the like.
Anyway, for your actual problem, I can't really see what's going on but one possible way to fix it would be to subclass ProductAdmin as well, and specifically set the model attribute to your subclassed model.