Extended User Model migrate - python

I want to extend my user model to hold a profile picture.
I am aware that you can create a new model and link it with foreign keys but since every type of user in my application has a Picture i figured i could add it to the user itself.
I extended the user in models.py:
class ExtendedUser(AbstractUser):
user_picture = models.ImageField(upload_to=housemate_image_path, null=True, blank=True)
Then i registered the model with the admin:
admin.site.register(ExtendedUser, UserAdmin)
And set my settings.py to:
AUTH_USER_MODEL = 'houses.ExtendedUser'
When i migrate i get:
houses.extendeduser (referred to by fields: account.EmailAddress.user, admin.LogEntry.user)
I assume it has something to with circular dependencies mentioned here and Django is proposing to create two migrations for this, but I don't understand how to go about it, can somebody help me out with this?

Related

How to assign a user to a model in my database

from django.db import models
from datetime import datetime
from django.contrib.auth import get_user_model
User = get_user_model()
class Blog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
headline = models.CharField(max_length=250)
content = models.CharField(max_length=2050)
time_created = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.user.username
every time I migrate this
"(venv) PS C:\Users\user\Desktop\APPS\web_app_project> python manage.py makemigrations"
I always get this message:
"It is impossible to add a non-nullable field 'user' to blog without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit and manually define a default value in models.py.
Select an option:"
How do I go about this
Because you've added the non-nullable field user to Blog Django needs to add a user to all instances of blogs in the database, both new ones and existing. If you've created a blog instance in the database, what should Django do with its new user column? That's what it is asking you.
Only if there is no data in the database or you are completely OK with losing data, you can migrate your app to zero with python manage.py migrate <your app name> zero (You might want to reverse to migration besides zero. You can read more about reverse migrations). This will effectively undo all of your migrations for that app. You can then delete the existing migrations for that app and run makemigrations again. Django will no longer complain about the non-nullable field user, as this results in a migration that creates a Blog table with a user field, instead of a migration that attempts to add a user field to an existing Blog table. Once again, do not do this unless you are OK with losing data. This should never be done if your app is already running in production, but it is OK if you have never deployed the app and have no "real" data, and you are still in the initial development phase. Also, make sure you have a backup of deleted migrations in case you need to add them back.
As others have suggested, you can create a default user model that is used as the one-time default to add users to Blogs. For example (in Django shell)
from django.contrib.auth import get_user_model
User = get_user_model()
user = User(username='default_blog_user')
user.set_unusable_password() # Nobody should be able to log in as this user
user.save()
print(user.id) # keep this ID
Then, in the migration, you can use whatever that user.id value was as the one-time-default. But this once again assumes that you haven't deployed to production, as the one-time-default and the IDs in development and production may not match.
If you have already deployed to production, I think the only thing you can do is make the user field nullable for the sake of your migration, but assert that it is not null in your programming logic. For example, by adding a validator to the field.
Side note: instead of running get_user_model in your models module, you should do this:
from django.conf import settings
class Blog(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
# etc.
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.
source
You could probably get away with adding the user manually by using the python shell• python manage.py shell then import the required models.
Read more from a similar question here:
How to use the python shell
https://stackoverflow.com/a/5150535/15383032
Maybe add a UUID to your User Model and make the fields that require a user in other models a CharField that stores the Users UUID.

Foreign key model in Django Admin

I have two user roles in Django:
Commercials
Sellers
I have created two models, Seller Model has a ForeignKey field to Commercials (every seller has a commercial related to). When I register the models in admin I can create Commercials and related sellers using StackedInline, TabularInline etc.
The problem I have is I need to associate users to this models in order to authenticate, login, etc. In admin I need to create a user (in an inline way, not dropdown box)
This is my code:
In models.py:
class Commercial(models.Model):
name = models.CharField(max_length=255, null=True)
user = models.OneToOneField(User, null=True)
class Seller(models.Model):
name = models.CharField(max_length=255, null=True)
commercial = models.ForeignKey('Commercial')
user = models.OneToOneField(User, null=True)
In admin.py:
class SellerAdmin(admin.StackedInline):
model = Seller
extra = 1
class CommercialAdmin(admin.ModelAdmin):
inlines = [SellerAdmin]
admin.site.register(Commercial, CommercialAdmin)
I need to edit, create, users etc. related to this models inline not in a modal window, Is there any way?
There is no way to make a reverse relation (so to say) in the form of Inlines. The Django admin panel doesn't have that ability by default.
What you could do is unregister the default UserAdmin, create a new Admin panel by inheriting the original one, and add this Seller as an Inline. There is still the issue that Django doesn't support multiple inlines, hence, you will not be able to use the Commercial model in the same admin page.
To fix that, you could refer to this information from the doc which shows how to overwrite the automatically created ModelForm for a particular ModelAdmin.
This will however not be that helpful as they are a lot of work. I would rather suggest implementing a workaround in how your application is used, rather than complicating it this much. Depends on the needs of the project, whether you need to go through this much trouble
Django nested inlines library might help you.

Django: Including standard User table as foreign key in my models?

I am designing a Django 1.8 application in which I have the concept of trials and assessors. I will have six assessors, who will use the Django admin to log in and make assessments.
I want each trial to have two attached assessors. How can I use the Django User model in models.py to ensure that the assessors are Users, and can be managed using the full power of Users?
Right now I have this, in which the assessors are not Users, but are just ordinary models:
class Assessor(models.Model):
name = models.CharField(max_length=200)
class Trial(models.Model):
title = models.CharField(max_length=800)
publication_date = models.DateField()
first_assessor = models.ForeignKey(assessor)
second_assessor = models.ForeignKey(assessor)
I want the assessors to be Users, so that I can manage them in the usual way through the User tables, but I don't know how to make this change.
They probably don't need any custom fields on top of the standard User attributes.
(NB: I don't need full-on permissions management within the admin, it's OK for any assessor to be able to edit the trial.)
UPDATE: Apologies, this is rather hard to explain! I don't care about the Django front-end at all, only the admin. I want a user to be able to log into the admin, see all the trials on which they are a primary assessor, and edit those trials. I'm not sure if it's best to do this with the User model, or not.
Instead of two foreign keys add a manytomany relation from Trail to user. Later, if you want you can add more assessors to a trail.
You can do like:
from django.contrib.auth.models import User
class Trial(models.Model):
title = models.CharField(max_length=800)
publication_date = models.DateField()
assessors = models.ManyToManyField(User,related_name="trials")
You can add assessors to Trial like:
trial = Trial.objects.get(id=give-trial-id)
user = User.objects.get(id=give-assessor-id)
trail.assessors.add(user)
You can get more info about manytomany here
I just saw your UPDATE. Any one who logs in to admin will have access to all objects of all models.
In your case all assessors who login to admin will have access to all trails irrespective of they are assigned to it or not.
If you want Filter django admin by logged in user then refer this question

django best approach for creating multiple type users

I want to create multiple users in django. I want to know which method will be the best..
class Teachers(models.Model):
user = models.ForeignKey(User)
is_teacher = models.BooleanField(default=True)
.......
or should I use..
class Teacher(User):
is_teacher = models.BooleanField(default=True)
.......
or I have to make custom user model...
Which will be good on creating multiple type users...??
Django doesn't have multiple users - it only has one user and then based on permissions users can do different things.
So, to start off with - there is only one user type in django. If you use the default authentication framework, the model for this user is called User, from django.contrib.auth.models.
If you want to customize user behavior in django, there are three things you can do:
Customize how you authenticate them. By default, authentication is done using a database where passwords are stored. You can authenticate against facebook/google etc. or against your existing user database - for example, with ActiveDirectory if you are on a Windows network.
Create custom permissions, and based on these permissions, restrict what functions users can execute. By default, on every model - django will add basic permissions "can edit", "can delete", "can read". You can create your own and then check if the user has these specific permissions.
You can store extra information about the user, along with whatever normally is stored by django. There are two ways to do this, depending on how much customization you need. If everything django provides by default works for you, and all you want to do is store extra information about the user you can extend the user model - in previous versions this was called creating a custom profile. The other option you have is to create your own User model, if you want deeper customization. The most common use of a custom user model is if you want to use an email address as the username.
You don't have to do all three, in fact sometimes all you want to do is store some extra information or have them authenticate using their email address; in some applications you have to modify all three places.
In your case, since all you want to do is store extra information about a user, you would need to extend the user model, by creating a model that references User (note: you don't inherit from User):
class Profile(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=200, default='Computer Science')
is_teacher = models.BooleanField(default=False)
is_student = models.BooleanField(default=True)
# .. etc. etc.
One approach I was following with Django 1.7 (works with 1.6 too) is to subclass AbstractUser
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
balance = models.DecimalField(default=0.0, decimal_places=2, max_digits=5)
To use your model you need to set it to be the one used for authentication in settings.py:
AUTH_USER_MODEL = 'your_app.User'
Also note that you will now have to use settings.AUTH_USER_MODEL when referencing
your new User model in a relation in your models.
from django.db import models
from django.conf import settings
class Transaction(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL) # ForeignKey(User) will not work

get user profile in django

hello i'm new in python and django
I need a view that get current user profile I know I shoud use get_profile from User but I don't know how to use it . i read the django document and It didn't help me.
this is what I found from doc:
from django.contrib.auth.models import User
profile=request.user.get_profile()
Django's documentation says it all, specifically the part Storing additional information about users. First you need to define a model somewhere in your models.py with fields for the additional information of the user:
models.py
from django.contrib.auth.models import User
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
accepted_eula = models.BooleanField()
favorite_animal = models.CharField(max_length=20, default="Dragons.")
Then, you need to indicate that this model (UserProfile) is the user profile by setting AUTH_PROFILE_MODULE inside your settings.py:
settings.py
...
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
...
You need to replace accounts with the name of your app. Finally, you want to create a profile every time a User instance is created by registering a post_save handler, this way every time you create a user Django will create his profile too:
models.py
from django.contrib.auth.models import User
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
accepted_eula = models.BooleanField()
favorite_animal = models.CharField(max_length=20, default="Dragons.")
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
Accessing the Profile
To access the current user's profile in your view, just use the User instance provided by the request, and call get_profile on it:
def your_view(request):
profile = request.user.get_profile()
...
# Your code
Basically django User models will provide access only for the fields ( firstname,lastname,email,password,is_staff,is_active,last_login).
However if we want to add any extra fields to this model, say we need to add a new column named dateofbirth for every user, then we need to add a column named DOB into User model. But this is not possible as we aren't able to edit django User models.
To achieve this either
1.We can have a separate new table with email id & DOB column, such that a column in User model is mapped with a column in the new table. But this will create a new db instance for every db request. Say if u want to find the DOB of a customer,
First we need to fetch the value of mapped id of a customer from the
User table.
WIth the above value, get DOB from the new table.
In the second method,
Instead of using django User model, use your own customize model with all the fields needed. However if any updation related to security or some enhancement made to django User model we can't use it directly. We need to do more code changes at our end( wherever we use our customize models.) This will be a bit pain for a developer to identify the code & make changes.
To overcome the above issues, django introduce django profile which is very simple and more flexible. The advantages are
Updation/enhancement to the User model can be applied without modifying the code much
No need of creating new db instance to fetch the extra values.
Since the field has onetoone mapping deletion of data from one table will delete others also.
More secure, since we use django models ( no sql injection)
How to Use this:
In settings.py create a variable AUTH_PROFILE_MODULE = "appname.profiletable"
In models.py, create a new table with the fields needed and make sure that the id in User model is onetoone mapped with new table.
create a signal which inserts a row into the new table whenever a new entry is added into User model.
The value in the new table can be accessed using User object itself.
Say, we created a new table extrauser which has DOB, emailid. To find the DOB of a customer, use
a=User.objects.get(email='x#x.xom')
a.get_profile().DOB will give the dateofbirth value from extrauser table.
Hope the above details make you clear in understanding django profile. Incase of any help further, let me know. I have used django profile in my project.
Old question but I thought anyone seeing it today may benefit from this:
Django 1.5 adds the ability to - easily - extend the User model. This may be preferable as you now only got one object to deal with rather than two! Seems the more modern way.
https://hurricanelabs.com/blog/django-user-models/
You need to specify which class is your "Profile" by setting AUTH_PROFILE_MODULE = 'accounts.UserProfile' (for example)
https://docs.djangoproject.com/en/1.4/topics/auth/

Categories

Resources