Creating Custom User Backends in Django - django

I have a Shops model and would like each shop to be able to login to my application. Following as best I can the guide at http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/ and various other googlings, I've got part of the way there, but I've run into a problem. When I try to login as a shop, I get the following error:
OperationalError at /login/
(1054, "Unknown column 'shops.user_ptr_id' in 'field list'")
Shops model:
class Shops(User):
shop_id = models.AutoField(primary_key=True)
shop_code = models.CharField(unique=True, max_length=5)
shop_type_fk = models.ForeignKey(ShopTypes,
null=True,
db_column='shop_type_id',
blank=True)
address_fk = models.ForeignKey(Addresses, db_column='address_id')
phone_number = models.CharField(max_length=30)
#email = models.EmailField(max_length=255, blank=True)
description = models.TextField(blank=True)
does_gift_aid = models.NullBooleanField(null=True, blank=True)
objects = UserManager()
class Meta:
db_table = u'shops'
I've sync'd the database, so surely it should have made the column user_ptr_id. Does anyone know where I'm going wrong?

"I've sync'd the database, so surely it should have made the column user_ptr_id."
What makes you think that? Especially in light of this clear statement in the docs for syncdb:
Syncdb will not alter existing tables
syncdb will only create tables for
models which have not yet been
installed. It will never issue ALTER
TABLE statements to match changes made
to a model class after installation.
Changes to model classes and database
schemas often involve some form of
ambiguity and, in those cases, Django
would have to guess at the correct
changes to make. There is a risk that
critical data would be lost in the
process.
If you have made changes to a model
and wish to alter the database tables
to match, use the sql command to
display the new SQL structure and
compare that to your existing table
schema to work out the changes.

It does sound like you had an existing shops table before changing it to inherit from User (as Daniel notes), and syncdb does not update the schema for existing tables.
You need to drop the table and then run syncdb, if possible. Otherwise you need to go into your database and add the user_ptr_id field manually, if you know how to do that. The definition should look something like this:
"user_ptr_id" integer NOT NULL UNIQUE REFERENCES "auth_user" ("id")

Related

Fixing django inspectdb after importing postgresql sample database

Context:
I'm playing around with setting up a DRF project using the postgresql sample database located here: Postresql Sample DB
Problem:
The sample database is already set up with intermediate tables film_category and film_actor. When using manage.py to inspectdb it generates these intermediate tables explicitly (FilmCategory and FilmActor) and they serve no purpose in the code as they only contain the ids for the two related fields. If I were to create them using the Django ORM I could just declare:
class Film(models.Model):
...
actors = models.ManyToManyField(Actor, related_name='films')
Django creates these tables "behind the curtain" so they take up no space in my code. I attempted to just set up a ManyToManyField like so:
actors = models.ManyToManyField(Actor, db_table='film_actor', related_name='films')
categories = models.ManyToManyField(Category, db_table='film_category', related_name='films')
When attempting to migrate, however, this fails giving me the following error:
psycopg2.errors.DuplicateTable: relation "film_actor" already exists
I don't think I want to create this ManyToManyField without explicitly telling it which db_table to use because I believe that would generate an entirely new intermediate table and I lose access to all the data already stored in those intermediate tables in the original sample database.
I was able to get it to work without errors and the expected operations function normally by doing:
actors = models.ManyToManyField(Actor, through='FilmActor', related_name='films')
But now I have an explicitly defined FilmActor and FilmCategory model sitting in my models.py that I cannot remove without causing errors:
class FilmActor(models.Model):
actor = models.ForeignKey(Actor, models.CASCADE)
film = models.ForeignKey(Film, models.CASCADE)
last_update = models.DateTimeField()
class FilmCategory(models.Model):
film = models.ForeignKey(Film, models.CASCADE)
category = models.ForeignKey(Category, models.CASCADE)
last_update = models.DateTimeField()
Has any dealt with explicitly defined intermediate tables generated from an existing DB with inspectdb? Is there a way to get rid of those models that were generated while still allowing the normal ManyToMany operations? Technically what I want to do is working, I just feel like having those two intermediate tables explicitly declared as models in my code when they have no additional data (other than "last_update") feels icky.

Django 1.4 Multiple Databases Foreignkey relationship (1146, "Table 'other.orders_iorder' doesn't exist")

I have a Foreign Key from one model into another model in a differente database (I know I shouldn't do it but if I take care properly of Referential Integrity it shouldn't be a problem).
The thing is that everything works fine...all the system does (relationships on any direction, the router takes care of it) but when I try to delete the referenced model (which doesn't have the foreign key attribute)...Django still wants to go throught the relationship to check if the relationship is empty, but the related object is on another database so it doesn't find the object in this database.
I tried to set up on_delete=models.DO_NOTHING with no success. Also tried to clear the relationship (but it happens clear doesn't have "using" argument so I it doesn't work either). Also tried to empty the relationship with delete(objects...), no success.
Now I am pretty sure the problem is in super(Object,self).delete(), I can not do super(Object,self).delete(using=other_database) because the self object is not in another database just the RelatedManager is. So I don't know how to make Django to understand I don't want even to check that relationship, which by the way was already emptied before the super(Object,self).delete() request.
I was thinking if there is some method I can override to make Django avoid this check.
More graphical:
DB1: "default" database (orders app)
from django.db import models from shop.models import Order
class IOrder(models.Model):
name = models.CharField(max_length=20, unique=True, blank=False, null=False)
order = models.ForeignKey(Order, related_name='iorders', blank=True, null=True)
DB2: "other" database
class Order(models.Model):
description = models.CharField(max_length=20, blank=False, null=False)
def delete(self):
# Delete iOrder if any
for iorder in self.iorders.using('default'):
iorder.delete()
# Remove myself
super(Order, self).delete()
The problem happens when supper(Order.self).delete() is called, then it can not find the table (iorder) in this database (because it is in 'default')
Some idea? Thanks in advance,
I already resolved my issue changing super(Order,self).delete() with a raw SQL delete command. Anyway I would love to know if there is a more proper way of doing this

Django Two foreign key

I have two models: UserProfile (extended from user) and Cv. I created another model that have two foreign key that come from theses models.
class cv(models.Model):
user = models.ForeignKey(User, unique=True)
cv_d= models.TextField(max_length=1100)
...
class cvv(models.Model):
user = models.ForeignKey(User)
cv= models.ForeignKey(cv)
date = models.DateTimeField(auto_now=True)
In my view, I am trying to insert value on cvv:
...
obj = cv.objects.get(pk=id,active=True)
add=cvv(user=request.user, cv=obj)
add.save()
But, I am getting the following error:
(1452, 'Cannot add or update a child row: a foreign key constraint fails
How can I insert theses 2 foreign key on my model?
Welcome to one of the many reasons why you shouldn't use MySQL. This happens most often when you have one table that is MyISAM and one table that is InnoDB. Since myISAM doesn't support FK constraints all hell breaks loose when django creates a FK between the tables.
The fix is to either make both tables InnoDB or MyISAM and not to mix them. Or even better drop the bad RDMS for something not MySQL.

ManyToManyField and South migration

I have user profile model with M2M field
class Account(models.Model):
...
friends = models.ManyToManyField('self', symmetrical=True, blank=True)
...
Now I need to know HOW and WHEN add each other as a FRIEND
And I created a model for that
class Account(models.Model):
...
friends = models.ManyToManyField('self', symmetrical=False, blank=True, through="Relationship")
...
class Relationship(models.Model):
""" Friends """
from_account = models.ForeignKey(Account, related_name="relationship_set_from_account")
to_account = models.ForeignKey(Account, related_name="relationship_set_to_account")
# ... some special fields for friends relationship
class Meta:
db_table = "accounts_account_friends"
unique_together = ('from_account','to_account')
Should I create any migration for this changes or not ?
If you have any suggestions you are feel free write their here.
Thanks
PS: accounts_account table already contain records
First off, I'd avoid using the db_table alias if you can. This makes it harder to understand the table structure, as it is no longer in sync with the models.
Secondly, the South API offers functions like db.rename_table(), which can be used by manually editing the migration file. You can rename the accounts_account_friends table to accounts_relation (as Django would name it by default), and add the additional columns.
This combined gives you the following migration:
def forwards(self, orm):
# the Account.friends field is a many-to-many field which got a through= option now.
# Instead of dropping+creating the table (or aliasing in Django),
# rename it, and add the required columns.
# Rename table
db.delete_unique('accounts_account_friends', ['from_account', 'to_account'])
db.rename_table('accounts_account_friends', 'accounts_relationship')
# Add extra fields
db.add_column('accounts_relationship', 'some_field', ...)
# Restore unique constraint
db.create_unique('accounts_relationship', ['from_account', 'to_account'])
def backwards(self, orm):
# Delete columns
db.delete_column('accounts_relationship', 'some_field')
db.delete_unique('accounts_relationship', ['from_account', 'to_account'])
# Rename table
db.rename_table('accounts_relationship', 'accounts_account_friends')
db.create_unique('accounts_account_friends', ['from_account', 'to_account'])
models = {
# Copy this from the final-migration.py file, see below
}
The unique relation is removed, and recreated so the constraint has the proper name.
The add column statements are easily generated with the following trick:
Add the Relationship model in models.py with foreign key fields only, and no changes to the M2M field yet.
Migrate to it
Add the fields to the Relationship model.
Do a ./manage.py schemamigration app --auto --stdout | tee final-migration.py | grep column
Revert the first migration.
Then you have everything you need to construct the migration file.
The way you've got it coded there, you're manually defining a model which does the same job as the m2m join table that Django will have automatically created for you. The thing is, the automatically created table will be called accounts_relationship_friend.
So, what you're doing there will create a model that tries to duplicate what the ORM has done under the surface, but it's pointing at the wrong table.
If you don't need an explicit join model, I would leave remove it from your codebase and not create a migration to add it, and instead use the M2M to find relationships between friends. (I'm not thinking about this too deeply, but it should work).
If, however, you want to do something special with the Relationship model you have (eg store attributes about the type of relationship, etc), I would declare the Relationship model to be the through model you use in your Friend.friends m2m definition. See the docs here.

Django reading old model?

I changed the model, synced the db, and now when i do:
Prs = Products.objects.filter(PrName__icontains='bla')
I get the error:
ERROR: column search_products.pr_name does not exist
LINE 1: SELECT "search_products"."id", "search_products"."pr_name", ...
But pr_name was the old model, this is how the new model looks like:
class Products(models.Model):
PrName = models.CharField(max_length=255)
PrDescription = models.CharField(max_length=4000)
PrPrice = models.DecimalField(max_digits=5, decimal_places=2)
PrCompany = models.ForeignKey(Companies)
def __str__(self):
return self.PrName
Why am i getting this error? I synced the db 100 times, checked all the code, there is no reference to pr_name anywhere?
Have you tried restarting your server? If you are using anything other than the development server, you'll probably need to do that manually after making changes like this.
Unfortunately the thing you try to do is not supported by django out of the box :-(
but you can do it ether by adding a db_column to the fields or by exporting the data, removing the table from the database, edit the export file, recreate the database table and reimporting the data.
Also look at the various schema evolution solutions out there