How to set unique_together for a user field - django-models

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.

Related

Django Admin won't save TextFields as NULL, unlike CharFields

good_field = models.CharField(max_length=256, null=True, default=None, blank=True, unique=True)
bad_field = models.TextField(null=True, default=None, blank=True, unique=True)
The good_field can be saved as blank and will end up as a NULL in the DB (which is important because of the unique=True but the bad_field gets saved as '' which violates the unique constraint.
Seems this was fixed for CharFields several years ago but for some reason not fixed for TextFields. Is it possible to fix this for TextFields too or was their some architectural reason it was only fixed for CharFields.
I tried fixing it in the model, but the admin form is doing the unique testing (instead of letting the DB do that work) and my model level patching never gets a chance.
Is there a way to remove the unique validation from the admin form and let the DB do it's job?

Cascade delete in Google datastore for ReferenceProperty objects

Is there a concept of having the Datastore in Google App Engine carry out cascade deletes where ReferenceProperty has been used? I understand than the Datastore in GAE is not a relational database. However, consider a simple model where blog posts can be liked by users.
class Post(db.Model):
subject = db.StringProperty(required=True)
content = db.TextProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
created_by = db.ReferenceProperty(User, required=True,
collection_name='posts')
and:
class Like(db.Model):
post = db.ReferenceProperty(Post, required=True, collection_name='likes')
user = db.ReferenceProperty(User, required=True, collection_name='likes')
When it comes to deleting a post, I want all "likes" to be deleted also.
def delete(self, post_key):
""" Deletes a post from the datastore """
db.delete(post_key)
# TODO: Should really delete any corresponding likes
# and comments too (else they're be orphaned)
So, must I code these deletions of likes myself, or can GAE do it automatically?
Thanks for any assistance that anyone could provide to increase my understanding.
There is no cascaded/recursive delete in the datastore, you have to implement it yourself.
These might help (same goal, different reason):
How to delete an entity including all children
Recursive delete in google app engine

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

Creating ManyToMany reference between db.Model and NDB

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.

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