I need to use a bi-directional relationship in Mongoengine which is something like the below.
from mongoengine import *
class Notification(Document):
desc = StringField()
from_user = ReferenceField('User')
class User(Document):
Name = StringField()
notifications = ListField(EmbeddedDocumentField(Notification))
I know we can put single quoted class name there when the class has not yet defined.
from_user = ReferenceField('User')
However, we got a problem here. Seems like in runtime it interprets our class as mongoengine.django.auth.user instead of our custom user class. (This is just what I guess but in runtime during debug mode I find that it misinterprets it as mongoengine.django.auth.user although the record in the collections should belong to the custom user class)
So is there any way for me to specify a fully qualified class name there?
Thanks!
In this instance you'd need to declare the User class after the Notification class.
Internally mongoengine uses a class registry, which is populated via the Document metaclass. Unfortunately, namespacing isn't the same as in the java world (I never thought I'd say that!) so as far as I know its not possible to determine the full location name for a class eg: myapp.models.User
Are you using the django User class? as well as another User class - this will cause issues with the registry as currently you can only have one class per name.
Related
I have two Django models, one that stores promotion codes and another that tracks who redeemed a particular promotion code. I'm trying to create an instance method that determines whether or not a specific user has redeemed a specific code. The problem is that I'm not seeing one of my PromotionManager methods, 'redeemed_by_user'. Here are my classes:
from django.contrib.auth.models import User
from django.db import models
class PromotionManager(models.Manager):
def redeemed_by_user(self, promotion, user):
redemption_count = PromotionRedeemed.objects.filter(promotion=promotion, redeemer=user).count()
if redemption_count == 1:
return True
elif redemption_count == 0;
return False
else:
raise ValueError('Invalid redemption count')
class Promotion(models.Model):
code = models.CharField(max_length=16)
objects = PromotionManager()
class PromotionRedeemed(models.Model):
promotion = models.ForeignKey('Promotion')
user = models.ManyToManyField(User)
If I start the the Django extension shell_plus and do the following:
In [1]: user = User.objects.get(username='smith')
In [2]: promotion = Promotion.objects.get(code='bigsale')
and then I do this:
In [3]: dir(promotion)
I don't see the redeemed by user method. I was under the impression that I could move methods like this from my class to a custom manager class. Is that not the case? If so, can anyone explain why? As I understand it, class manager methods are supposed to act on table-level queries and class intance methods on row-level objects. Isn't objects.filter acting on the table level? I tried moving the method back to the Promotion class and I can see it there but I'd just like to understand why I can't see it in the manager class.
Whatever you are seeing is absolutely correct but there is small correction that you should make. When you do a dir(some_instance) then you see a property named objects .
objects = PromotionManager()
This line sets all the manager methods to the objects property so if you try to access the method via some_instance.objects.method_name then you will be able to access it although you can't use it because Django doesn't allow this. You will see an error like manager methods are not accessible from instances. dir is supposed to show only those methods which are accessible from your model instance.
From the docs,
A Manager is the interface through which database query operations are provided to Django models. By default, Django adds a Manager with the name "objects" to every Django model class.
A model’s manager is an object through which Django models perform database queries. Each Django model has at least one manager, and you can create custom managers in order to customize database access.
Adding extra manager methods(custom managers) is the preferred way to add “table-level” functionality to your models whereas for “row-level” functionality use model methods.
Objects is a special attribute through which you query your database. It’s an instance of the class django.db.models.Manager; it’s where all the default methods for performing queries against the entire model class — all(), get(), filter(), etc.
The dir() function, with an argument, attempt to return a list of valid attributes for that object.
If you dir(promotion), promotion is an instance of Promotion Model object. It returns the attributes of a Promotion instance, which includes the objects attribute. But, you defined objects as PromotionManager(), and the redeemed_by_user() is a method of the Manager instance.
If you dir(promotion.objects) , django would raise an error, AttributeError: Manager isn't accessible via Poke instances. Because, its true. objects is a Manager available at the class level, not to the instances.
From the docs,
Managers are accessible only via model classes, rather than from model instances, to enforce a separation between “table-level” operations and “record-level” operations.
So, if you dir(Promotion.objects), you could see all custom methods defined in the Manager instance of the model.
You use dir on the wrong object.
Moreover, you replaced default manager with yours.
The first manager applied to a model class has special meaning for Django, and is a default one, so add own manager this way, please:
objects = models.Manager()
<your_custom_name> = PromotionManager()
Below are my models and I am using InheritanceManager of django-model-utils. i decided the field user to be in the subclasses because i need to access the Child subclass via the relation like user.child1_set.all().
class Mother(models.Model):
objects = InheritanceManager()
class Child1(Mother):
user = models.ForiegnKey(User)
class Child2(Mother):
user = models.ForiegnKey(User)
the problem is, when i want to query starting from Mother class, there seems to be no query that makes it.
i've tried these codes.
Mother.objects.filter(user=SOMEUSER)
Mother.objects.filter(child1__user=SOMEUSER)
Mother.objects.select_subclasses().filder(user=SOMEUSER)
Mother.objects.select_subclasses().filder(child1__user=SOMEUSER)
any advice would be appreciated.
I simplify my code structure, which contains two models:
# created by third part app, not Django one
# but we share same DB, so i have access to this one
class A(models.Model):
title = models.TextField()
# other fields ...
class Meta:
manage = False
class B(models.Model):
model_a = models.OneToOneField(A, related_name='+')
# other fields, to extend model A functionality
Is this a good way to extend third part app model A with my additional fields and methods? Now i have problem to sync this models true one-to-one field. Since I don't have access to trigger model A creation.
In ideal world i should have CarA and CarB. And CarB = CarA relation should be created if CarB exists.
I base this idea on Django 1.5 user extension. Is this clear enough? Or should i do something else?
You could use a property to create the B instance on access if it doesn't exist yet, ie,
class A(models.Model):
title = models.TextField()
# other fields ...
class Meta:
manage = False
#property
def b(self):
if not hasattr(self, "__bcache"):
self.__bcache, created = B.objects.get_or_create(model_a = self)
return self.__bcache
It seems like you're new to both Python and Django so let's explain quickly...
First, the "#property" part: it's a decorator that turns the following function into a computed attribute - IOW you use it as an attribute (myA.b.whatever), and under the hood it turns it into a method call (myA.b().whatever). It's not strictly required here, we would have used an explicit getter (the same method named get_a()) but it's cleaner that way.
Then our method implementation: obviously we don't want to hit the database each time someone looks up A.b, so
first we check if an attribute named __bcache ("b" "cache") is set on the current instance.
if not, we call B.objects.get_or_create(a_model=self) which will either retrieve the existing B instance for this A instance or create one if none exists yet and we store this B instance as self.__bcache so next call will retrieve it directly from __bcache instead of hitting the database.
and finally we return self.__bcache that is now garanteed to exists and point to the related B instance.
The person on our team who initially taught us django (and has subsequently left) utilized a controllers.py file for helper functions. A lot of these functions are directly related to classes. I prefer to use #staticmethod to house these helpers with the classes they're related to. For example, rather than doing this:
# controllers.py
def process_entry():
# do some exciting stuff that might not have to do with an instance
Called like this:
from myapp.controllers import process_entry
process_entry()
I'd prefer this:
# models.py
class Entry(models.Model):
name = CharField...
# some other fields
#staticmethod
def process_entry():
# do some exciting stuff that might not have to do with an instance
Called like so:
from myapp.models import Entry
Entry.process_entry()
Is there a preferred, standard way to deal with situations like this or is it just personal preference? Does anyone else utilize a controllers.py file? What goes in there?
Thanks.
EDIT:
Possibly a better example, commissions.
# models.py
class Commission(models.Model):
check = ForeignKey
payment = ForeignKey
# other fields
class Check(models.Model):
# fields
class Payment(models.Model):
# fields
Any time a Check or Payment instance is modified an adjustment as to be made to any related Commission instances or any time someone wants to manually run commissions, they can do so. So where should run_commissions() go? I prefer this, but apparently this shouldn't be encapsulated in a data-related model?
# models.py
class Commission(models.Model):
check = ForeignKey
payment = ForeignKey
# other fields
#staticmethod
def run_commissions():
# do stuff
Static methods are used for grouping related functions in one class (mostly for factory methods), beside that, there is no difference between static method and function.
BUT. In your example you are assigning behavior to DATABASE model. DATABASE models are not LOGIC models, and you should separate them from your app logic. Anyway, controllers is also a bad name in that matter.
I'm not sure what process_entry does, but if it's only changing one Entry entity, then it can be named: Entry.process(), but NOT Entry as DB model! just another Entry class. However if that function does more than just changing Entry, then it shouldn't be assigned to Entry entity, but made as a service function.
How would you go about creating a relationship between two different entity models?
When I try this I get an error:
class Spec(ndb.Model):
userKey = ndb.KeyProperty(kind=User)
class User(ndb.Model):
specs = ndb.KeyProperty(kind=Spec, repeated=True)
The error as I understand stems from referencing User before it is defined.
I did the following to solve it, and I use a get_by_id, but I do not like this solution:
class Spec(ndb.Model):
userKey = ndb.IntegerProperty()
class User(ndb.Model):
specs = ndb.KeyProperty(kind=Spec, repeated=True)
How would you solve this so I can define my models as in the first example? Even better, how would you go about to define each class in its own file/module.
I tried following this article, but it seems to be be outdated and not relevant to ndb.
https://developers.google.com/appengine/articles/modeling
Thank you
As the docs show, the kind argument can be a string. So use kind='User'.