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
Related
I have been using django-river(https://github.com/javrasya/django-river) application within my app (https://github.com/rupin/WorkflowEngine)
I have used the Django rest framework in my application and would like to get the data from the django-river tables. The name of the table is State.
My serializer is as follows
from river.models import State
from rest_framework import serializers
class StateSerializer(serializers.Serializer):
class Meta:
model = State
fields = ['id', 'label']
Also, my API view is as follows
from rest_framework import generics
from workflowengine.riverserializers.StateSerializer import StateSerializer
from river.models import State
class StateList(generics.ListAPIView):
serializer_class = StateSerializer
def get_queryset(self):
return State.objects.all()
Through the Admin console, I have added 11 states inside my state table, which I have checked with pgadmin.
When i access the API through the browser, I get 11 empty sections in my API ( no error, just the data is missing).
I cant seem to understand how the 11 data points presented in the API are empty. That it presented 11 elements, but no data, which is pretty weird.
I think you need to use:
class StateSerializer(serializers.ModelSerializer):
I have created a REST API using DRF, and that works well enough. The frontend is a simple page that allows data to be viewed and updated. Now I am trying to add more interactivity to the site using WebSockets with django-channels. The Channels system is fairly simple to use and also works nicely.
However the issue I am now facing is trying to combine all of the moving pieces to work together. My idea is that the initial page refresh comes through the REST API, and any subsequent updates would automagically come through a WebSocket after every update (with the help of post_save signal). I have nice DRF Serializers for all my models, but alas those do not work without a Request object (for instance HyperLinkedIdentityField):
AssertionError: `HyperlinkedIdentityField` requires the request in the serializer context. Add `context={'request': request}` when instantiating the serializer.
So my question is, how do I somehow create/fake a proper Request object that the Serializers want when trying to serialize my model in a signal handler?
Edit
The more I think about this, the more obvious it becomes that this is not exactly the right way to go. There is no way to craft a single, generic Request object for the serializers, since the model updates which trigger them can come from any source. Thus it would not make sense to even try creating one. I think I have to separate the "base" serializers (without any hyperlinks) and use those to send updates to the clients. Since the hyperlinks won't ever change, I think this is the proper way to go.
In case anyone might be interested, here is how I solved the issue. The main bits and pieces of code are below.
First a simple model (myapp/models.py):
from django.db import models
class MyModel(models.Model):
name = models.TextField()
Then the serializers (myapp/serializers.py):
from rest_framework import serializers
MyModelSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModel
fields = ('url', 'id', 'name')
extra_kwargs = {'url': {'view_name': 'mymodel-detail'}}
MyModelBaseSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('id', 'name')
And the views (myapp/views.py):
from rest_framework import viewsets
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer
class MyModelViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
And finally the Channels message consumer (myapp/consumers.py):
import json
from django.db.models.signals import pre_save
from django.dispatch import receiver
from channels import Group
from myapp.models import MyModel
from myapp.serializers import MyModelBaseSerializer
def ws_add(message):
message.reply_channel.send({"accept": True})
Group("mymodel").add(message.reply_channel)
def ws_disconnect(message):
Group("mymodel").discard(message.reply_channel)
#receiver(post_save, sender=MyModel)
def mymodel_handler(sender, instance, **kwargs):
Group("mymodel").send({
"text": json.dumps({
"model": "mymodel",
"data": MyModelBaseSerializer(instance).data
})
})
I have omitted things like urls.py and routing.py but those are not relevant to the issue. As can be seen, the regular view uses the normal MyModelSerializer which is includes the URL, and then the update handler MyModelBaseSerializer has only fields which are not dependent on any Request object.
I have defined declared my own Strategy to Select a Stock and a price as described in http://django-oscar.readthedocs.io/en/releases-1.1/topics/prices_and_availability.html
Everything worked fine until I had the need to import a custom model class that I created in the catalogue app.
My goal was to access this custom model for the price selection strategy.
in /apps/partner/strategy I tried to import the model like this:
CountrySpecificProductInformation = get_model('catalogue', 'CountrySpecificProductInformation')
this call raises a Model not Registered exception:
File "/home/matyas/virtenvs/oscar/local/lib/python2.7/site-packages/oscar/core/loading.py", line 250, in get_model
return apps.get_registered_model(app_label, model_name)
File "/home/matyas/virtenvs/oscar/local/lib/python2.7/site-packages/django/apps/registry.py", line 260, in get_registered_model
"Model '%s.%s' not registered." % (app_label, model_name))
LookupError: Model 'catalogue.CountrySpecificProductInformation' not registered.
my Installed apps settings look like this:
INSTALLED_APPS = ['...'] +
oscar.get_core_apps(['apps.catalogue', 'apps.promotions', 'apps.dashboard',
'apps.dashboard.catalogue', 'apps.partner', 'apps.payment', 'apps.dashboard.partners',
'apps.shipping', 'apps.checkout', 'apps.search'])
I am using django-oscar 1.3 with Django 1.9.9
Oscar has its own importing, system that is necessary to be able to overwrite any part of any app of the e-commerce solution.
The strategy class gets imported early on the when the server starts, and some models are not registered at that time yet.
The solution was to import the module not at the top of the module in the import section, but instaed only in the method where the models are necessary. (In my case that was the the select_stockrecord method:
from oscar.core.loading import get_class, get_model
CountrySpecificProductInformation = get_model('catalogue',
'CountrySpecificProductInformation')
def select_stockrecord(self, product):
CountrySpecificProductInformation = get_model('catalogue', 'CountrySpecificProductInformation')
Country = get_model('catalogue', 'Country')
It is not a perfect solution but I prefer this rather than writing raw sql queries directly to the database.
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.
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