I need achieve something like this:
from oscar.apps.catalogue.abstract_models import AbstractProduct
from oscar.apps.catalogue.models import ProductClass
Product(AbstractProduct):
#property
display(self):
if self.product_class = ProductClass.objects.get(pk=1):
#do something
else:
#do something else
But when I do a from catalogue.models import Product elsewhere I invariably get the default Oscar Product and not my overridden Product with the display() property.
I believe this is because the built-in Oscar Product is being registered before my custom one when I do the import ProductClass.
However to achieve the functionality I need it's vital I have access to ProductClass in the forked version of Product!
How can I get around this catch-22?
When overriding Oscar models you need to move any non-abstract imports below the class definitions that are meant to replace models that come with Oscar. Here's an example.
In your case it should be safe to just move the models import below:
from oscar.apps.catalogue.abstract_models import AbstractProduct
Product(AbstractProduct):
#property
display(self):
if self.product_class == ProductClass.objects.get(pk=1):
#do something
else:
#do something else
from oscar.apps.catalogue.models import *
The display property will continue to work since by the time it is called for the first time, the module scope will already contain all the necessary models.
I've changed the import to * to make sure that all other models are loaded from Oscar.
Please note that the star import will inevitably try to import the Product model as well but Oscar will notice that a model by that name is already registered and will simply discard the other definition. It is ugly and confusing but that's the Oscar's recommended method.
Related
Let's say I have two models, in different apps. App Two knows about app One, but not the other way around:
# one/models.py
from django.db import models
class One(models.Model):
pass
# two/models.py
from django.db import models
from one.models import One
class Two(models.Model):
one = models.ForeignKey(One)
I also have One registered in the admin site:
# one/admin.py
from django.contrib import admin
from .models import One
admin.site.register(One)
How do I register Two as an Inline on One's admin page, without introducing a circular dependency between the two apps?
You can do this pretty simply, providing you don't mind accessing a 'private' attribute on the ModelAdmin. (Attributes beginning with an underscore are treated as private by convention.)
# two/admin.py
from django.contrib import admin
from one.models import One
from .models import Two
class TwoInline(admin.StackedInline):
model = Two
admin.site._registry[One].inlines.append(TwoInline)
I had the same issue but solved it more gentle way.
# one/admin.py
class OneAdmin(admin.ModelAdmin):
model = One
admin.site.register(One, OneAdmin)
# two/admin.py
class TwoInline(admin.TabularInline):
model = Two
import one.admin
class OneAdmin(one.admin.OneAdmin):
inlines = [TwoInline]
admin.site.unregister(One)
admin.site.register(One, OneAdmin)
As you see I extended the original ModelAdmin from first app and added inlines from second app. Don't forget to unregister the model from first app before registering it again.
It's safe and much better than to access private member of the class as was suggested.
I would try the following:
# one/admin.py
from django.contrib import admin
from one.models import One
from two.models import Two
class TwoInline(admin.StackedInline):
model = Two
class OneAdmin(admin.ModelAdmin):
inlines = [TwoInline,]
admin.site.register(One, OneAdmin)
You can read more at the docs.
I'm using django-taggit to tag some objects, Bookmarks. The Bookmarks have a boolean is_private attribute.
When fetching a list of the most frequently-used tags I can do this:
Bookmark.tags.most_common()
But how would I get the most frequently-used tags ignoring all the tags on is_private Bookmarks? If it helps, there's a Bookmark.public_objects manager which only returns the non-private Bookmarks.
I stumbled across the answer while looking through the django-taggit docs and code for something else. You can set a custom Manager on your model's tags attribute, and use this to add extra functionality.
So, previously, my Bookmark model had this:
from django.db import models
from taggit.managers import TaggableManager
class Bookmark(models.Model):
# Other attributes here
tags = TaggableManager
I've now changed that to this:
from django.db import models
from taggit.managers import TaggableManager
from .managers import _BookmarkTaggableManager
class Bookmark(models.Model):
# Other attributes here
tags = TaggableManager(manager=_BookmarkTaggableManager)
And then in myapp/managers.py I have this:
from django.db import models
from taggit.managers import _TaggableManager
class _BookmarkTaggableManager(_TaggableManager):
def most_common_public(self):
extra_filters = {'bookmark__is_private': False}
return self.get_queryset(extra_filters).annotate(
num_times=models.Count(self.through.tag_relname())
).order_by('-num_times')
That most_common_public() method is a copy of django-taggit's standard most_common() method but with the addition of passing that extra_filters to the queryset.
Then when I want the list of most common tags, but excluding private Bookmarks, I use this:
Bookmark.tags.most_common_public()
There might be a different method -- I'm a little uneasy about duplicating the entire query from most_common() for instance -- but this seems to work.
I'm getting started with Django. I can't get the admin to work (it used to work, I'm not sure what update made it break...).
As soon as I register a model in the admin, the website crashes with this error on any URL:
'module' object is not iterable
In the trace it happens to bug on this:
/Library/Python/2.7/site-packages/django/contrib/admin/sites.py in register
for model in model_or_iterable:
admin_class
<class 'django.contrib.admin.options.ModelAdmin'>
options
{}
model_or_iterable
<module 'model.Branch' from '...../farmpower/src/model/Branch.pyc'>
self
<django.contrib.admin.sites.AdminSite object at 0x1098196d0>
I've tried with different models, in that example, with Branch (code in admin.py):
from django.contrib import admin
from models import *
admin.site.register(Branch)
models.py:
import Page, Promotion, Branch, Contact
Branch.py
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Branch(models.Model):
name = models.CharField
[...]
class Meta:
app_label = "model"
db_table = "cms_branch"
def __unicode__(self):
return self.name
Thank you for your help !
There are several things in your code that are not very neat. One of them might lead to the error you're seeing, though I don't know which one of 'em is it.
You use relative imports (from models import ...). It is more robust do do an absolute import like from yourapp.models import ...).
You use a "star import": from models import *. You don't really know what you're importing exactly in the file where you're doing this. Also automatic code checkers (like pyflakes) cannot check whether you're missing imports anymore.
You mention models.yml as the filename. That's not a .py extension, so python doesn't do a thing with that one.
The app name you set in the Meta on your models is model. Note that "models" and "model" are quite django-internal names. So having an app called "model" with a "models.py" could easily go wrong. Why is the app not yourapp or something like that?
Here are some ways in which it could go wrong:
Star import: perhaps you've imported a different admin in models.py? Which overwrites, through the star import, the one in admin.py?
The models.yml: if that really is the name, what does from models import * return? With a non-existing models.py? Try to import Branch explicitly: from models import Branch and see if it fails.
App name: if your app is really called "model", a relative import from models import * could perhaps get you the top-level "model" module instead of the "model.models" that you mean in case you mis-type something.
It's your
from models import *
it should be
from appName.models import className
I have two models, say, Question and Topic.
I am trying to add methods to the Question model's custom manager, e.g. some method that filters by Topic.
I can't seem to use the other manager's code for this (cannot import Topic either, so I can't do Topic.objects...)
In class QuestionManager
def my_feed(self, user):
topics = TopicManager().filter(user=user) # 1st approach
#topics = Topic.objects.filter(user=user) # 2nd line
# do something with topics
class TopicManager
....
Using 1st approach, I get the following error:
virtualenv/local/lib/python2.7/site-packages/django/db/models/sql/query.pyc in get_meta(self)
219 by subclasses.
220 """
--> 221 return self.model._meta
222
223 def clone(self, klass=None, memo=None, **kwargs):
AttributeError: 'NoneType' object has no attribute '_meta'
I can't use the 2nd line since I can't import Topic, since Topic depends on the TopicManager in this file. Is there a workaround for this?
You can't use a manager directly, in any circumstance. You always access it via the model class.
If you can't import the model at the top of the file because of a circular dependency, you can simply import it inside the method.
You should be able to place this at the bottom of the managers.py module:
# Prevent circular import error between models.py and managers.py
from apps.drs import models
In your manager classes you can reference other models using models.<modelname>, and this should work, avoiding the circular import.
For example:
class QuestionManager(Manager):
def my_feed(self, user):
topics = models.Topic.objects.filter(user=user)
# do something with topics
# Prevent circular import error between models.py and managers.py
from apps.drs import models
This works because you are importing the module, not the model classes, which results in a lazy import. By the time the function is run the module will be imported and everything will work.
You could also load models by name using django.apps.get_model():
from django.apps import apps
apps.get_model('my_app', 'MyModel')
Details here
For example:
from django.apps import apps
class QuestionManager(Manager):
def my_feed(self, user):
topics = apps.get_model('my_app', 'Topic').objects.filter(user=user)
# do something with topics
I've got sorl-thumbnail up and running in templates with Redis to store the thumbnails. Great stuff!! However, I would like to have thumbails in my Admin. I used the example in the documentation (see below) but with no luck.
from gallery.models import Photo
from django.contrib import admin
from sorl.thumbnail.admin import AdminImageMixin
class PhotoAdmin(AdminImageMixin, admin.ModelAdmin):
pass
admin.site.register(Photo, PhotoAdmin)
What am I doing wrong?
I do something very similar and it works for me. However, I use a slightly different method, importing my admin from a utils/admin.py in my site base instead, allowing easy inheritance across my models with other apps such as django-reversion, django-guardian, and django-markitup.
gallery/admin.py:
#from django.contrib import admin
from utils import admin
from gallery.models import Photo
class PhotoAdmin(admin.ModelAdmin):
#your customizations
admin.site.register(Photo,PhotoAdmin)
utils/admin.py:
from django.contrib.admin import *
from django.db import models
from sorl.thumbnail.admin import AdminImageMixin
class ModelAdmin(AdminImageMixin, ModelAdmin):
pass
Your model's ImageFields need to be sorl's ImageField (from sorl.thumbnail.fields import ImageField) instead of the standard django.db.models.ImageField.
This field is a drop-in replacement, so just updating this should fix the issue, or at least it did for me. If you are using South for database migrations, note that it will generate one for this, which is fine.