I have two different app that has separate models that inherits from AbstractionBaseUser like below
# in doctor/models.py
...
class Patient(AbstractBaseUser):
email = models.EmailField(blank=True, unique=True)
phone_number = models.IntegerField(blank=False, unique=True)
USERNAME_FIELD = 'phone_number'
REQUIRED_FIELD = ['phone_number', 'email']
...
# in Patient/models.py
...
class Patient(AbstractBaseUser):
email = models.EmailField(blank=True, unique=True)
phone_number = models.IntegerField(blank=False, unique=True)
USERNAME_FIELD = 'phone_number'
REQUIRED_FIELD = ['phone_number', 'email']
...
Both models have different fields
# in settings.py
AUTH_USER_MODEL = [
'doctor.Doctor',
'patient.Patient'
]
I tried to do this but in making migration it tells me that it must be a single model
AssertionError: ForeignKey(['doctor.Doctor', 'patient.Patient']) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
I read docs but I couldn't find any help
How can I fix this and how can I have multiple AUTH_USER_MODEL
how can I have multiple AUTH_USER_MODEL.
You don't. There is one user model. It would also make all procedures more complicated. What if a the same email address occurs in both the Doctor and Patient model? Then how would you log in such person?
You can however make multiple extra models with a ForeignKey to the user model. We can for example use the default user model:
# settings.py
# …
AUTH_USER_MODEL = 'auth.User'
# …
You can of course also specify a basic user model yourself. But it should be one user model.
Then both the Doctor and Patient model can have a one-to-one relation to the User model:
from django.db import models
from django.conf import settings
class Doctor(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
# … extra doctor fields …
as well as a patient:
from django.db import models
from django.conf import settings
class Patient(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
# … extra patient fields …
You can then check for a user if it is a doctor by accessing the .doctor attribute:
from django.contrib.auth.decorators import login_required
#login_required
def some_view(request):
try:
doctor = request.user.doctor
except AttributeError:
# … user is not a doctor …
pass
pass
This also allows that a User is both a Doctor and a Patient for example. This may look odd at first. But later it is possible that you introduce more roles, and it is not impossible that the same user is assigned multiple roles, for example doctor and supervisor of a department.
Related
In the following mode in my project, I want to assign the author variable of class upon the creation of model, on user end this could be done via request.user but as the class can be only instantiated from the admin area, this doesn't work.
class Blog(models.Model):
title = models.CharField(max_length=300)
content = RichTextField()
author = models.ForeignKey(User, related_name="Author", auto_created= True, on_delete=
models.CASCADE)
date = models.DateTimeField(auto_now_add= True)
The auto_created=… field [Django-doc] is about model inheritance, it does not add the logged in user: the model layer is request unaware, and there is not per se a "logged in user". You thus remodel this to:
from django.conf import settings
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=300)
content = RichTextField()
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='blogs',
on_delete=models.CASCADE,
editable=False,
)
date = models.DateTimeField(auto_now_add=True)
In the model admin for the Blog model, you can work with:
from django.contrib import admin
#admin.register(Blog)
class BlogAdmin(admin.ModelAdmin):
# …
def save_model(self, request, obj, form, change):
obj.author = request.user
return super().save_model(request, obj, form, change)
Note: The related_name=… parameter [Django-doc]
is the name of the relation in reverse, so from the Blog model to the User
model in this case. Therefore it (often) makes not much sense to name it the
same as the forward relation. You thus might want to consider renaming the Author relation to blogs.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I have created the user Customer model. I migrated the model to syn with the database. However I am getting an error of User has no customer.
click to profile page through http://127.0.0.1:8000/profile But after adding profile code for every user I am getting the below error
Here is my code
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
full_name = models.CharField(max_length=200, null=True)
address = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return self.full_name
class CustomerProfileView(TemplateView):
template_name = "app/CustomerProfile.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
customer = self.request.user.customer
context['customer'] = customer
orders = Order.objects.filter(cart__customer=customer).order_by("-id")
context["orders"] = orders
return context
As the error says, you use a User object for which there is no related Customer object.
You thus have to construct a Customer record for all users that have no Customer. You can for example do this in a data migration [Django-doc] with:
python manage.py makemigrations --empty app_name
in the data migration you can then create a Customer for every user without a Customer:
from django.db import migrations
def create_customers(apps, schema_editor):
Customer = apps.get_model('app_name', 'Customer')
User = apps.get_model('auth', 'User')
customers = [
Customer(user=user, full_name=None, address=None)
for user in User.objects.filter(customer=None)
]
Customer.objects.bulk_create(customers)
class Migration(migrations.Migration):
dependencies = [
('app_name', '1234_some_migration'),
]
operations = [
migrations.RunPython(create_customers),
]
and then run the migration to construct customer for all already existing users.
I have override the default User model in my app with AUTH_USER_MODEL.
Here is the user model I want to use in my app, which is tied closely to a legacy database:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
name = models.CharField(max_length=128, blank=True)
email = models.EmailField(unique=True)
password = models.CharField(max_length=128)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
normalized_email = models.EmailField(unique=True)
However, django complains that fields such as first_name, last_name, etc. are not provided. Is there a way to remove some of the existing fields in the User model? Or does specifying a custom user model only allow you to add additional fields on top of that? Is there a simple way to delete them, or do I basically have to add those fields (and ignore them) to our existing database in order to be able to use django with it?
AbstractUser is for when you want to add additional fields to Django's defaults. Use AbstractBaseUser if you don't want all those fields.
I'm using django-allauth and I want to be able to add new field to my User model.
What's the best way to do this as of you ?
I use userena. But I am sure that it will look almost the same ;)
class UserProfile(UserenaBaseProfile):
user = models.OneToOneField(User, unique=True)
city = models.CharField(max_length=32, blank=True, null=True)
in settings.py:
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
See the docs Storing additional information about users, Make a model with OneToOneField relation to User.
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.")
I have an application that makes use of Django's UserProfile to extend the built-in Django User model. Looks a bit like:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
# Local Stuff
image_url_s = models.CharField(max_length=128, blank=True)
image_url_m = models.CharField(max_length=128, blank=True)
# Admin
class Admin: pass
I have added a new class to my model:
class Team(models.Model):
name = models.CharField(max_length=128)
manager = models.ForeignKey(User, related_name='manager')
members = models.ManyToManyField(User, blank=True)
And it is registered into the Admin:
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
admin.site.register(Team, TeamAdmin)
Alas, in the admin inteface, when I go to select a manager from the drop-down box, or set team members via the multi-select field, they are ordered by the User numeric ID. For the life of me, I can not figure out how to get these sorted.
I have a similar class with:
class Meta:
ordering = ['name']
That works great! But I don't "own" the User class, and when I try this trick in UserAdmin:
class Meta:
ordering = ['username']
I get:
django.core.management.base.CommandError: One or more models did not validate:
events.userprofile: "ordering" refers to "username", a field that doesn't exist.
user.username doesn't work either. I could specify, like image_url_s if I wanted to . . . how can I tell the admin to sort my lists of users by username? Thanks!
This
class Meta:
ordering = ['username']
should be
ordering = ['user__username']
if it's in your UserProfile admin class. That'll stop the exception, but I don't think it helps you.
Ordering the User model as you describe is quite tricky, but see http://code.djangoproject.com/ticket/6089#comment:8 for a solution.
One way would be to define a custom form to use for your Team model in the admin, and override the manager field to use a queryset with the correct ordering:
from django import forms
class TeamForm(forms.ModelForm):
manager = forms.ModelChoiceField(queryset=User.objects.order_by('username'))
class Meta:
model = Team
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
form = TeamForm
This might be dangerous for some reason, but this can be done in one line in your project's models.py file:
User._meta.ordering=["username"]
For me, the only working solution was to use Proxy Model. As stated in the documentation, you can create own proxy models for even built-in models and customize anything like in regular models:
class OrderedUser(User):
class Meta:
proxy = True
ordering = ["username"]
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
After that, in your model just change Foreign Key to:
user = models.OneToOneField(OrderedUser, unique=True)
or even more suitable
user = models.OneToOneField(OrderedUser, unique = True, parent_link = True)