Using Custom User DB Structure in Mysql for Django 1.8 - python

I have a question regarding the table structure for User if I am extending its functionalities, using a MySQL database.
Given the models.py file
class LibraryUser(models.Model):
user_id = models.OneToOneField(User)
is_catalogue_subscriber = models.IntegerField(default=1)
is_research_subscriber = models.IntegerField(default=1)
library_membership_number = models.CharField(max_length=64)
I have a table structure for SQL
CREATE TABLE library_user(
user_id int(10) primary key
is_catalogue_subscriber integer(1) DEFAULT 1
is_research_subscriber = integer(1) DEFAULT 1
library_membership_number = varchar(16)
)
So now, when I fire up my server and access the accounts in the admin page, Django is throwing an error:
Exception Type: OperationalError
Exception Value:
(1054, "Unknown column 'library_user.id' in 'where clause'")

Use
user = models.OneToOneField(User, primary_key=True)
i.e. drop the _id in the attribute name.
In case you simply want to define a richer user model (i.e. add more attributes) you can
use a one-to-one relationship to a model containing the fields
for additional information. This one-to-one model is often called a
profile model, as it might store non-auth related information about a
site user. For example you might create a LibraryUser model:
from django.contrib.auth.models import User
class LibraryUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
is_catalogue_subscriber = models.IntegerField(default=1)
is_research_subscriber = models.IntegerField(default=1)
library_membership_number = models.CharField(max_length=64)
Assuming an existing LibraryUser Fred Smith who has both a User and LibraryUser model, you can access the related information using Django’s standard related model conventions:
>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.libraryuser.department
Then to add the profile model’s fields to the user page in the admin do
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import LibraryUser
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class LibraryUserInline(admin.StackedInline):
model = LibraryUser
can_delete = False
verbose_name_plural = 'libraryuser'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (LibraryUserInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
All taken from the official docs

What you are missing is that by default django models automatically include an id field that maps to models.AutoField().
You need to specify that your DB table id is user_id instead of id.
https://docs.djangoproject.com/en/1.8/topics/db/models/#automatic-primary-key-fields
You want to make your user_id the primary key. It should work by adding primary_key=True to that field, like:
class LibraryUser(models.Model):
user_id = models.OneToOneField(User, primary_key=True)
is_catalogue_subscriber = models.IntegerField(default=1)
is_research_subscriber = models.IntegerField(default=1)
library_membership_number = models.CharField(max_length=64)

Related

Do i need to update AUTH_USER_MODEL in my settings.py?

I am creating my own users, Restaurant and Customer. I have extended the AbstractUser class and then created a OneToOneField field for each user. I am wondering if I need to add the AUTH_USER_MODEL in my settings.py. And also wondering what that does exactly...
What I was planning on doing was adding to my settings.py:
AUTH_USER_MODEL = 'myapp.Customer','myapp.Restaurant'
Do I have the right idea here?
My models.py:
class User(AbstractUser):
is_restaurant = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
class Restaurant(models.Model):
user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
restaurant_name = models.CharField(max_length=50)
def __str__(self):
return self.restaurant_name
class Customer(models.Model):
user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
address = models.CharField(max_length=200)
def __str__(self):
return self.user.get_full_name()
No. AUTH_USER_MODEL isn't expecting a tuple, so this won't work.
In any case, Restaurant and Customer are not your user model; your subclassed User is. That's what you should be putting in that setting.
I would suggest create single user table instead of three different tables and add type as restaurant, customer, admin etc. And add only one table into settings file. this won't lead any further issues authentication etc. Having single user table is always robust. In your case having three tables seems not good to maintain.
========== UPDATE ===========
Create model for user named as CustomUser (or name which you feel better) and extends to User Model of Django using AbstractBaseUser,PermissionsMixin. like
class CustomUser(AbstractBaseUser): have all fields which user table has already. and add your desired table to bifurcate type of restaurant and
customer have type field with choices option.
For further help you can check section https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#substituting-a-custom-user-model

Django is failing to save data related to User table. It says it doesn't have `mymodel_set` attribute

I have a model linked to Django User model but when I try saving to that model using User instance, it says 'User' object has no attribute 'mymodel_set'
My models.py:
from django.contrib.auth.models import User
from django.db import models
class MyModel(models.Model):
user = models.OneToOneField(User, blank=True, null=True, related_name='mymodel')
name = models.CharField(max_length=14, blank=True, null=True)
My views.py:
from django.contrib.auth.models import User
from myapp.models import mymodel
def register(request):
#gets data here from template
user = User(username=reg_username, password=reg_password)
user.save()
user.mymodel_set.create(name= display_name)
return HttpResponse('Success')
If the related object existed, you would use mymodel, but it does not exist and the relationship is void, so it cannot be accessed via the user. Create it first and set the relationship to that user:
mymodel = MyModel.objects.create(name=display_name, user=user)
# ^^^^ set related user
The _set suffix is usually used for reverse ForeignKey relationships and not for OneToOne relationships.
Also note that the related_name on the user field was already specified as mymodel, and the related field can now be accessed from the User model via user.mymodel

Django - use same column for two foreign keys

I have three models:
class UserProfile:
user_id = OneToOneField(User, related_name='profile')
name = CharField
class User:
# standard django model
class Channel:
owner = ForeignKey(User)
And now, I want to get channels filtering on user name. So what I can do is:
Channel.objects.filter(owner__profile__name__icontains='foo')
But this joins User table and then joins UserProfile, which is not the best, because I would like to join UserProfile table on user_id instead (I would have one join instead of two)
I tried to add another foreign key to model like this:
class Channel:
owner = models.ForeignKey(
User,
db_column='owner_id',
)
owner_profile = models.ForeignKey(
UserProfile,
db_column='owner_id',
to_field='user_id')
But Django doesnt like it....
posts.Post: (models.E007) Field 'owner_profile' has column name 'owner_id' that is used by another field.
HINT: Specify a 'db_column' for the field.
Is there any clean workaround for this?
Django content type framework would do the trick
in your case:
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Channel(models.Model):
owner_ct = models.ForeignKey(to=ContentType, on_delete=models.CASCADE, blank=True, null=True) # foreign key table indicator (User,Profile) in your case
owner_content = models.CharField(max_length=64, blank=True, null=True) # uuid(foreign key) will be placed here as string
owner_object = GenericForeignKey('owner_ct', 'owner_content') # bridge to object
class User(models.Model):
channels = GenericRelation(to='Channel', object_id_field='owner_content', content_type_field='owner_ct',related_query_name='channels') # User.channels will be available
class Profile(models.Model):
channels = GenericRelation(to='Channel', object_id_field='owner_content', content_type_field='owner_ct',related_query_name='channels') # Profile.channels will be available

foreignkey (user) in models

I read the docs and this post... Django - Foreign Key to User model
I followed what it said and I still cannot get it to work. When I try to run the migrations I get this error in the traceback...
django.db.utils.ProgrammingError: column "author_id" cannot be cast automatically to type integer
HINT: You might need to specify "USING author_id::integer".
I just don't know how to go about fixing that error.
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class BlogCategory(models.Model):
'''model for categories'''
title = models.CharField(max_length=30)
description = models.CharField(max_length=100)
class BlogPost(models.Model):
'''a model for a blog post'''
author = models.ForeignKey(User)
date = models.DateField()
title = models.CharField(max_length=100)
post = models.TextField()
Don't use the User model directly.
From the documentation
Instead of referring to User directly, you should reference the user
model using django.contrib.auth.get_user_model()
When you define a foreign key or many-to-many relations to the user model, you should specify the custom model using the AUTH_USER_MODEL setting.
Example:
from django.conf import settings
from django.db import models
class Article(models.Model):
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
If you created a custom User model, you would use setting.AUTH_USER_MODEL, if not you can go ahead an use User model
Referencing Django User model
the column "author_id" doesn't exist, looks like is the same problem from here : Django suffix ForeignKey field with _id , so to avoid this traceback you may use :
author = models.ForeignKey(User, db_column="user")
I do not know the "settings.AUTH_USER_MODEL" approach but a well-known approach and commonly used is the "Auth.User" model. Something like this on your end.
from django.contrib.auth.models import User
class BlogPost(models.Model):
'''a model for a blog post'''
author = models.ForeignKey(User)
date = models.DateField()
title = models.CharField(max_length=100)
post = models.TextField()

how to extend model User?

please help to solve this problem
I expanded in django1.6 User model as follows:
class UserProfile(User):
......
......
family = models.CharField(
max_length=30,
blank=True,
)
skype = models.CharField(
max_length=50,
blank=False,
)
email_address = models.EmailField(
max_length=50,
blank=True,
)
.....
....
objects = UserManager()
resulting in adminpanel appeared a form with the above fields. after filling the data is stored in the database table "app_userprofile". This table is linked to the table "auth_user" using the foreign key.
the problem is that the table "auth_user" fields "username" and "password" empty . but each user needed.
please tell me how to do so after the new user registration ( of the admin panel and from the site ) data "username" and "password" fell into the table "auth_user"
I think you need to use AbstractUser model. If you inherit UserProfile from User model you will get 2 tables with same fields, and when you fill app.UserProfile password field - value doesn`t appear in auth.User table.
Of course you can do like this: https://stackoverflow.com/a/23390975/1761844 but better way - create your own custom user:
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
... your custom fields ...
and add to your settings.py
AUTH_USER_MODEL = 'app.CustomUser'
after this you will get user model with your custom fields. You can import it in your apps like this:
from django.contrib.auth import get_user_model
User = get_user_model()
and make foreign keys like this:
owner = models.OneToOneField(settings.AUTH_USER_MODEL)
Link to django documentation: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-django-s-default-user
Use a one to one field, User.profile will create the Profile object the first time user.profile it is accessed:
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, unique=True)
User.profile = property(lambda u: Profile.objects.get_or_create(user=u)[0])
First, change UserProfile, like it was mentioned in the previous answer. After that, check this answer: https://stackoverflow.com/a/4565957 as it explains how to combine user and user profile forms on a single admin page. Then you will be able to add both user and his/her profile with a single save.
There is also other way to solve your problem: you can define a custom user model with all the fields you need, combining username, password, family and other data in a single table. Check out this page for reference: https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#specifying-a-custom-user-model.

Categories

Resources