I am using django-nonrel and django-mongodb engine.
In engine's documentation, it says that it supports django's Meta options.
I tried using unique_together in a model as such:
class Bottler(models.Model):
location = models.CharField(max_length=20)
source = models.CharField(max_length=20)
transactionID = models.CharField()
class Meta:
unique_together = (("location","source"),)
However this doesn't seem to have worked since I could create duplicates without any error being raised.
I know unique_together is enforced at the database level.
What does that translate to in MongoDB?
Do I have to validate it manually?
You need to run syncdb in order to sync database indices.
Somehow syncbd will not update your indexes in mongodb. What you can try (if possible in your situation) is to delete the collection and then run syncdb. In my case it did create the indexes then.
Related
Let's suppose I have the following model:
class Test(models.Model):
field_one = models.CharField(max_length=80)
Now, we have created 2-3 Model objects with field_one field.
p1 = Test(field_one="Object1")
p1.save()
p2 = Test(field_one="Object2")
p2.save()
Later, I realised that I need to add another field field_two to my Test model.
class Test(models.Model):
field_one = models.CharField(max_length=80)
field_two = models.IntegerField(default=3)
Now, Doing makemigrations & migrate
and running server.
which will prompt the following error
django.db.utils.ProgrammingError: column mainapp_test.field_two does not exist
I understand that this error occurs due to my 2 existing objects in PostGresDB doesn't have field_two column.
Is there any effective way to add field_two column to my existing objects with some default value? or How to solve this problem?
Django Version: 2.0
Django ORM DB: PostGresql
When you add a field to an existing model, you must either provide a default value in the code, or set it to null/blank = True, or provide a one-off default while migrating.
Since you are providing a default in the code, the migration should run without issues. At least from experience, I've added several BooleanFields with default=False to my existing model with thousands of entries, and I never got a ProgrammingError.
Have you tried shutting down the Postgres backend before running makemigrations and migrate? I would think Django would do this but that's the only thing I can think of. Also, obviously, shut down the Django server if it's still running.
I have the following model at Django:
class Community(models.Model):
name = models.CharField(max_length=255)
members = models.ManyToManyField(User, through='Membership')
date_created = models.DateTimeField(auto_now_add=True)
But when I check the structure of the table (using Postico for PostgreSQL) the field of date_created after applying the migrations shows no default.
I have also tried with explicitly default=date.today() but it does not work.
Any ideas what I am missing?
Thanks,
Pablo
EDIT
Great thanks to this post: How to make a script to insert data in my default sqlite3 database django
I was trying to populate the database via script using PostgreSQL driver, when it is way simpler importing the Django models a use the create method (also thanks to Daniel Roseman in the comments that led me find the post).
Maybe this question also is similar to something like "automatic execution of raw SQL code just before creating exact one special model in models.py with managed=False".
For example, I have 3 models in models.py (default User, UserTypes and relation between them):
from django.contrib.auth.models import User
class UserTypes(models.Model):
type = models.TextField(unique=True)
class Meta:
db_table = 'user_types'
class UsersHaveTypes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
type = models.ForeignKey(UserTypes, on_delete=models.CASCADE)
class Meta:
db_table = 'users_have_types'
unique_together = (("user", "type"), )
I have few types of users one of which is clients. Now I want to create endpoints "/clients", which will work as a usual model (CRUD).
Right now, I just add this in models.py:
class Clients(models.Model):
first_name = models.TextField(blank=True, null=True)
last_name = models.TextField(blank=True, null=True)
# all another fields from User model, which duplicated in the database view
class Meta:
managed = False
db_table = 'clients'
and then I make this by hand in my database backend:
Create database view
Create a function to make Insert, Update
and Delete
Create a trigger to trigger this functions.
It's a bunch of code and there is nothing special, all worked fine.
This all is to make working CRUD on "/clients" endpoint, so, for example, on "Creation", it will create User and automatically add a correct row to users_have_types table, which marks this user as "client".
Is there some more elegant and automatical way to make this? I move my Django project, and I need to create view, function, and trigger in the database backend again, which takes a lot of time (all by hand for every "type of users") and is an ugly decision.
I'm surprised, that nobody asked this question before, cause it's a good style of code database to make some views, and hide real table behind them. I know that Django can't create database view by self, but there must be a way to describe custom SQL code, which is used to create a table in the database. Maybe something with managers, I don't know (I'm a newbie in Django). Of course, it will be specific only for one database backend, but it's fine.
Filtering on Django GenericRelations has been implemented 4 years ago via https://code.djangoproject.com/ticket/22207 and supports now to filter from the related model:
class Issue(models.Model):
project_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=False, null=True)
project_id = models.PositiveIntegerField(blank=False, null=True)
project = GenericForeignKey('project_content_type', 'project_id')
class GitlabProject(models.Model):
issues = GenericRelation(
Issue,
related_query_name='generic_project',
content_type_field='project_content_type',
object_id_field='project_id',
)
and then:
issues = queryset.filter(generic_project__offers__members__in=[request.user])
We cannot use just project__offers_members - it would fail, as Django does not reversely resolve Generic Foreign Keys.
However what happens if we have another project model with the same related_query_name?
class JiraProject(models.Model):
issues = GenericRelation(
Issue,
related_query_name='generic_project',
content_type_field='project_content_type',
object_id_field='project_id',
)
I have tried setting the GenericRelation with the same related_query_name on all the different project models (i.e. Gitlab Project, Jira Project, etc.). However that results in Django picking up only the 'first' project model. The generic relation to all subsequent project models are ignored and as a result, issues that have instances set that do not belong to the 'first' project model are ignored and not part of the queryset.
I think Django should either support this or issue a warning or error (possibly when executing the makemigrations command), when multiple GenericRelations have the same related_query_name value set.
How can one filter efficiently across issues that have their project attribute set to instances of different models?
Seems like this should be "easy" or at least documented somewhere, I just cant find it.
Lets say I have a model:
class A(models.Model):
users = models.ManyToMany('auth.User', blank=True)
Now I want to migrate to have a through table to add fields to the ManyToMany relation...
class AUsers(models.Model):
user = models.ForeignKey('auth.User')
a = models.ForeignKey('A')
new_field = models.BooleanField()
class A(models.Model):
users = models.ManyToMany('auth.User', blank=True, through='AUsers')
Then I do:
% ./manage.py schemamigration app --auto
Not totally surprising, it tells me it is going to drop the original auto-created through table and create a new one for AUsers. What's the best practice at this point? Is there a decent way to migrate to the new through table? Do I use db_table in Meta? Do I just not use the through=... right away... then do a schemamigration --auto, then a datamigration to copy the current table (somehow, not sure...) and then add the through relation and let it kill the table?
What's the trick here? Is this really that hard?
You should be able to do this pretty easily.
First of all, make sure that the manual through table that you are creating has the same table name in the database as the one Django originally created automatically.
So, first, let's consider a manual through model before your change:
class AUsers(models.Model):
user = models.ForeignKey('auth.User')
a = models.ForeignKey('A')
class Meta:
db_table = 'appname_a_user'
That should be functionally (almost) identical to the ManyToManyField you used to have. Actually, you could make an empty migration and apply it, and then use --auto for your changes (but don't).
Now, add your field like you did in your sample code above, and then run ./manage.py schemamigration appname manual_through_table --empty. That will give you an empty migration named ####_manual_through_table.py.
In the migration itself, there will be a forwards and backwards method. Each one needs to be one line each:
def forwards(self, orm):
db.add_column('appname_a_user', 'new_field', self.gf('django.db.models.fields.BooleanField')(default=False))
def backwards(self, orm):
db.delete_column('appname_a_user', 'new_field')
That should get you what you are after.
If anyone comes across this question when trying to do the same thing with the moderns migration framework, here are the steps:
Create a new model class that exactly matches the built-in through table
Use the Meta class to set the table name to match the existing table
Generate a migration, which will create the new table and set it as the through for the field.
Without running that migration, edit it to wrap it in a migrations. SeparateDatabaseAndState migration, where the auto-generated steps are in the state_operations field and the database operations are empty.
Modify your through table, as required, making sure to generate new migrations as normal.
As mentioned in a comment, the first step may be simplified using db.rename_table as described here, which gives this through model:
class AUsers(models.Model):
user = models.ForeignKey('auth.User')
a = models.ForeignKey('A')
class Meta:
unique_together = (('user', 'a'),)
Then, create a migration with --auto (this way you'll have the names of the DB tables visible), and replace the content with:
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_table('appname_a_user', 'appname_auser')
def backwards(self, orm):
db.rename_table('appname_auser','appname_a_user')
I just applied it in my project without issues.