Creating ManyToMany reference between db.Model and NDB - google-app-engine

Changing question. I Want to apply ManyToMany relationship between db.Model and NDB.
example
NDB model
class my_NDB(search.SearchableModel):
.......
.......
db model
class Test(search.SearchableModel):
email = db.StringProperty()
created_by = db.IntegerProperty()
Can I apply ManyToMany relationship between these models?
EDIT:
Here is my User Model
class User(model.Expando):
"""Stores user authentication credentials or authorization ids."""
#: The model used to ensure uniqueness.
unique_model = Unique
#: The model used to store tokens.
token_model = UserToken
created = model.DateTimeProperty(auto_now_add=True)
updated = model.DateTimeProperty(auto_now=True)
# ID for third party authentication, e.g. 'google:username'. UNIQUE.
auth_ids = model.StringProperty(repeated=True)
# Hashed password. Not required because third party authentication
# doesn't use password.
email = model.StringProperty(required=True)
is_active = model.BooleanProperty(required=True)
password = model.StringProperty()
And Here is my Test db model
class Test(search.SearchableModel):
email = db.StringProperty()
created_by = db.IntegerProperty()
Now I want to apply manyToMany on Test. Is it possible?
Django style ManyToMany
created_by = models.ManyToManyField(User)

I see. I had to look up the Django ManyToManyField docs. IIUC you want a Test to be created by multiple users, and of course each user can create multiple tests. Have I got that right?
The way to do this would be to have a db.ListProperty(db.Key) in the Test class, so that the Test class has a list of keys -- where the keys point to User entities.
Now your User model is an NDB class, which complicates matters a bit. However the ndb Key class has an API for converting to and from db Keys:
If you have an ndb Key k, k.to_old_key() returns the corresponding db.Key.
If you have a db Key k, ndb.Key.from_old_key(k) returns the ndb.Key for it (it's a class method).
Hope this helps. Good luck!
PS. Please update your code to use from google.appengine.ext import ndb so you can write ndb.Expando, ndb.StringProperty, etc.

Related

How to set unique_together for a user field

I am learning Django. I am creating app where I have a model Employer.
In a database, I want to keep only one record for fields user and website.
I tried to use unique_together in my model but during migration I got the following error:
django.db.utils.IntegrityError: UNIQUE constraint failed: employer_employer.user_id, employer_employer.website
Can you please advice me what is a problem? Maybe this is not a good way how to do it?
Thanks!
class Employer(models.Model):
USER = settings.AUTH_USER_MODEL
user = models.ForeignKey(USER, default=1, on_delete=models.CASCADE)
company_name = models.CharField(max_length=200)
company_size = models.IntegerField(default=0)
website = models.CharField(max_length=200)
class Meta:
unique_together = ('user', 'website')
I tried to use unique_together in my model but during migration I got the following error: django.db.utils.IntegrityError: UNIQUE constraint failed: employer_employer.user_id, employer_employer.website
This means the migration is perfectly fine. It means there is already data in the database that violates the constraint, so you will first need to go through the fact that there are Employer objects in the database with the same user and the same website.
You can find such Users effectively with:
from django.db.models import Count
Employee.objects.values('user', 'website').annotate(count=Count('pk')).filter(
count__gt=1
)
then you will have to fix these Employer records.
Note: As the documentation on unique_together [Django-doc] says, the unique_together constraint will likely become deprecated. The documentation advises to use the UniqueConstraint [Django-doc] from Django's constraint
framework.

How to synchronize tables in Django?

In my database I want to synchronize two tables. I use auth_user(Default table provided by Django) table for registration and there was another table user-profile that contain entities username, email, age etc. How to autometically upadate the columns username and email in user-profile according to updation in auth_user table.
from django.contrib.auth.models import User
class profile(models.Model):
username = models.CharField(max_length = 30)
email = models.EmailField()
age = models.PositiveIntegerField()
auth_user_id = models.ForeignKey(User)
You can either modify the django registration code and include the code to save into your profile model on every new registration.
Or
You can set a signal on every save of User model. See the documentation.
def create_profile(sender, **kwargs):
if kwargs["created"]:
p = Profile(user=kwargs["instance"], ...)
p.save()
django.db.models.signals.post_save.connect(create_profile, sender=User)
create_profile() will be called every time any User object is saved.
In this example, I create Profile object only if a new User instance has been created. You can modify it to change existing Profile objects on every change in User instance, also.

Google App Engine Entity Ownership

I am writing an app for GAE in Python which stores recipes for different users. I have an entity called User in the datastore and an entity called Recipe. I want to be able to set the owner of each Recipe to the User who created it. Also, I want each User entity to contain a list of all Recipes belonging to that User as well as being able to query the Recipe database to find all Recipes owned by a particular User.
What is the best way to go about creating this parent/child type relationship?
Thanks
There are two main ways. (I am going to assume your using python which defines examples)
Option 1. Make the User the ancestor of all of their recipes
recipe = Recipe(parent=user.key)
Option 2. Use key property
class Recipe(ndb.Model):
owner = ndb.KeyProperty()
recipe = Recipe(owner=user.key)
all recipes for user with option 1
recipes = Recipe.query(ancestor=user.key)
all recupes for user with option 2
recipes = Recipe.query().filter(Recipe.owner == user.key)
Which one you use really depends a lot on what you plan to do with the data after creation, transaction patterns etc.... You should elaborate on your use cases. Both will work.
Also you should read up on transactions entity groups and understand them to really determine if you want to use ancestors https://developers.google.com/appengine/docs/java/datastore/transactions?hl=en .
If you use db.Model, to model one-to-many relationship, you can use the RefernenceProperty constructor and specify a collection_name. For example, one book may have many reviews.
class Book(db.Model):
title = db.StringProperty()
author = db.StringProperty()
class BookReview(db.Model):
book = db.ReferenceProperty(Book, collection_name='reviews')
b = Book()
b.put()
br = BookReview()
br.book = b # sets br's 'book' property to b's key
for review in b.reviews:# use collection_name to retrieve all reviews for a book
....
see https://developers.google.com/appengine/docs/python/datastore/datamodeling#references
Alternatively, you can use ndb's KeyProperty as in Tim's answer.
Also see
db.ReferenceProperty() vs ndb.KeyProperty in App Engine

One-to-Many relationship in ndb

I am reading up on Google app engine and preparing a sample to understand it better.
In a nutshell the user can record an entry for every day in the month, like a calendar.
And the user can view the entries on monthly basis. So no more than 30 ish at a time.
Initially I had used db and the one-to-many relationship was straight forward.
But once I came across the ndb, I realized there are two ways of modelling a one-to-many relationship.
1) The structured property seems to act like a repeated property on the User model. Does it mean if I retrieve one user, I would automatically retrieve all the records she has entered? (e.g. the entire year) This isn't very efficient though, is it? I guess the the advantage is that you get all related data in one read operation.
from google.appengine.ext import ndb
class User(UserMixin, ndb.Model):
email = ndb.StringProperty(required = True)
password_hash = ndb.TextProperty(required = True)
record = ndb.StructuredProperty(Record, repeated=True)
class Record(ndb.Model):
notes = ndb.TextProperty()
2) Alternatively I could use perhaps the more classic way:
class User(UserMixin, ndb.Model):
email = ndb.StringProperty(required = True)
password_hash = ndb.TextProperty(required = True)
class Record(ndb.Model):
user = ndb.KeyProperty(kind=User)
notes = ndb.TextProperty()
Which way is the better way in my use case?
The downside of using StructuredProperty instead of KeyProperty is that with StructuredProperty the limit on total entity size (1MB) applies to the sum of the User and all Records it contains (because the structured properties are serialized as part of the User entity). With KeyProperty, each Record has a 1MB limit by itself.

Use database view in Django

I saw the question can i use a database view as a model in django and tried it in my app, but that didn't work.
I created a view named "vi\_topics" manually and it had "id" column but I kept getting an error, even if I added "id" field explicitly, saying
"no such column: vi_topics.id"
Here is the definition of my model named Vitopic:
from django.db import models
class Vitopic(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author_name = models.CharField(max_length=200)
author_email = models.CharField(max_length=200)
view_count = models.IntegerField(default=0)
replay_count = models.IntegerField(default=0)
tags = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'vi_topics'
Note: I use sqlite3.
Try this:
http://docs.djangoproject.com/en/dev/ref/models/options/#managed
managed
Options.managed
New in Django 1.1: Please, see the release notes
Defaults to True, meaning Django will create the appropriate database tables in syncdb and remove them as part of a reset management command. That is, Django manages the database tables' lifecycles.
If False, no database table creation or deletion operations will be performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means. This is the only difference when managed is False. All other aspects of model handling are exactly the same as normal. This includes
Adding an automatic primary key field to the model if you don't declare it. To avoid confusion for later code readers, it's recommended to specify all the columns from the database table you are modeling when using unmanaged models.
If a model with managed=False contains a ManyToManyField that points to another unmanaged model, then the intermediate table for the many-to-many join will also not be created. However, a the intermediary table between one managed and one unmanaged model will be created.
If you need to change this default behavior, create the intermediary table as an explicit model (with managed set as needed) and use the ManyToManyField.through attribute to make the relation use your custom model.
For tests involving models with managed=False, it's up to you to ensure the correct tables are created as part of the test setup.
id = models.IntegerField(primary_key=True)

Resources