I'm trying to build a user profile which builds on the default Django user. I'm trying to extend the default user with an extra fields like this:
class MyMember(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL) #not sure about this
birthday = models.DateField()
USERNAME_FIELD = 'user' #how to use username field from default user?
REQUIRED_FIELDS = ['birthday',]
def __unicode__(self):
return self.username
But I'm getting this error: 'Manager' object has no attribute 'get_by_natural_key'? Why?
I would also like the USERNAME_FIELD to be the username from the default user. How?
Here's the UserProfile model class I use to extend the User model in my demo website:
#Private function required by image field.
def _get_upload_file_name_w_sub_dir(instance, filename):
return "uploaded_files/{0}{1}_{2}".format("profile_pic/", (str(time()).replace(".", "_"), filename))
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
# related_name is so you can reference *this* model as "user.profile"
# instead of "user.userprofile"
user = models.OneToOneField(User, related_name="profile")
# The additional attributes we wish to include.
year_discovered = models.IntegerField(blank=True,
verbose_name="Year you discovered Billy Joel's music/became a fan")
profile_picture = models.ImageField(upload_to=get_upload_profile_pic_file_name,
blank=True, null=True)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
Here is the official documentation on extending the user model.
This is how you would extend the default Django User model. You would want to use a ForeignKey, and then you can use dot notation to access the fields of the User model.
Here:
from django.contrib.auth.models import User
class MyMember(models.Model):
user = models.ForeignKey(User)
birthday = models.DateField()
def __unicode__(self):
# the default "username" field in the django user model
return self.user.username
Related
I have two models which doesn't have foreign key as relation but has the username column common.
class User(models.Model):
password = models.CharField(max_length=255)
email = models.EmailField(unique=True, blank=True)
username = models.CharField(max_length=255)
class SessionUser(models.Model):
username = models.CharField(max_length=255)
last_login = models.DateTimeField(auto_now=True)
I wanted to list all users in Django admin and once clicked on individual object it should list all the session of user. How can we link the object which doesn't have foregien key relationship?
Make username model field unique in User model.
and Add a session_users method in list_display of UserAdmin class
from django.utils.html import format_html
class UserAdmin(admin.Modeladmin):
# your user_admin model class
list_display = ['other_model_fields', 'session_users']
...
...
def session_users(self, obj):
redirect_url = ("%s?username=%s") % (reverse('admin:<app_name>_sessionuser_changelist'), obj.username)
return format_html('<a class="button" href="{}">Add/View</a>', redirect_url)
This will redirect with filtered data of SessionUser model-admin.
i think leaving out the foreign key is not a good idea since there are chances of some usernames to be similar to avoid that, unique=True condition should be added.
I've inherited from the AbstractBaseUser as follows:
class User(AbstractBaseUser):
"""
Main User model, inherits from AbstractBaseUser
"""
# Meta
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=40, unique=True) # equals to email
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True)
So each User is linked to one and only one Customer.
Now within a view I want to access the instance of the current logged in user within the request object and get the employee_of value to get a queryset that contains all users of that customer.
def render_employees(request):
"""
Renders the employees page of the dashboard
:param request:
:return:
"""
# Return the value for the current site for css specific classes
dashboard_site = 'employees'
# Query the employees
qs_employees = User.objects.filter(employee_of=request.user.employee_of) # doesn't find field
...
However the filter doesn't work because request.user.employ_of doesn't seem to return anything. My IDE even suggests e.g. username, date_joined etc. but not employee_of.
Why's that?
class Customer(models.Model):
"""
A table that stores static data about a customer, usually a legal company
"""
legal_name = models.CharField(max_length=50)
street = models.CharField(max_length=30)
street_number = models.CharField(max_length=3)
def __str__(self):
return self.legal_name
Update:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from applications.customer.models import Customer
from django.conf import settings
BaseUser = settings.AUTH_USER_MODEL
class User(AbstractBaseUser):
"""
Main User model, inherits from AbstractBaseUser
"""
# Relations
user = models.OneToOneField(BaseUser, related_name='user_profile', on_delete=models.CASCADE, null=True) # link to default user model
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True, blank=True)
I linked the user to the default user model via Django admin. However in the view im still not able to access employee_of within request.user
It seems that request.user is a different model. It's User model from django.contrib.auth. https://docs.djangoproject.com/en/4.0/ref/contrib/auth/#django.contrib.auth.models.User.
What you can do about it?
In our app we have UserProfile model that have OnetoOne relation to django User.
You can then store employee_of value there.
class UserProfile(AbstractBaseUser):
user = models.OnetoOneField("auth.User", related_name="user_profile", on_delete=models.CASCADE)
employee_of = models.OneToOneField(Customer, on_delete=models.SET_NULL, null=True)
and then access request.user employees using something like
request.user.user_profile.employee_of
I am making a movie watching website in which there are users and films and the user model has a ManyToMany Field that references the film model. it's called WatchList and an authenticated user can add any movie they want to this watchlist.
My problem is that I want an API that only gets the ID of a film and adds it to the user's watch list.
these are my models and serializers and I am trying to make a view to implement this API.
# models.py
class Film(models.Model):
filmID = models.AutoField(primary_key=True)
title = models.CharField(max_length=150)
# ...
class User(AbstractBaseUser, PermissionsMixin):
userID = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
email= models.EmailField(max_length=100, unique=True, validators=[EmailValidator()])
name = models.CharField(max_length=100)
watchList = models.ManyToManyField(Film)
objects = UserManager()
USERNAME_FIELD = 'username'
# serializers.py
class WatchListSerializer(serializers.ModelSerializer):
class FilmSerializer(serializers.ModelSerializer):
model = Film
fields = ('filmID', 'title',)
read_only_fields = ('filmID', 'title')
film_set = FilmSerializer(read_only=True, many=True)
class Meta:
model = get_user_model()
fields = ('userID', 'film_set')
read_only_fields = ('userID',)
# views.py
class WatchListAddView(...):
pass
The serializer can be changed. but this kind of shows what I want the api to be. the authentication validation part is already taken care of, so imagine that any request to the view is from an authenticated user.
I would not recommend patching this directly and instead create a separate endpoint for adding removing data to this field.
In your case it would look like this. I show just a small working example, you can adjust it to your needs
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
#action(detail=True,
methods=['POST'])
def add_film_to_watch_list(self, request, **kwargs):
film = get_object_or_404(klass=Film, filmID=kwargs.get('filmID'))
user = self.get_object()
user.watchList.add(film)
return Response("Success")
I'm working on a project on how to create Two users : buyers/Sellers for Web using Django as Backend.
I've started the app "users"
I've read the Django Documentation about CustomUserModel
But Honestly don't know where to start from.
Any Suggestions?
In my opinion, a Buyer might be a seller and a seller might be a Buyer.
There are some suggestions:
Create your own application named users (This will help you full control User object in future).
Set your AUTH_USER_MODEL settings to users.User: AUTH_USER_MODEL = 'users.User' As you defined.
Define model Seller - OneToOne -> User: This contains seller's properties, Just create when access via user.seller
Define model Buyer - OneToOne -> User: This contains buyer's properties, just create when access via user.buyer
class User(AbstractUser):
# Your user's properties
# Your user's method
#property
def buyer(self):
try:
return Buyer.objects.get(user=self)
except Buyer.DoesNotExist:
default_value_of_buyer = {}
# Or define default value at model fields
return Buyer.objects.create(user=self, **default_value_of_buyer)
#property
def seller(self):
try:
return Seller.objects.get(user=self)
except Seller.DoesNotExist:
default_value_of_seller = {}
# Or define default value at model fields
return Seller.objects.create(user=self, **default_value_of_seller)
class Buyer(models.Model):
"""
You can add this to admin page to make some actions with Buyer
"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, on_delete=models.CASCADE, related_name='buyer_profile')
# Other properties of Buyer
def __str__(self):
return "%s's Buyer profile" % self.user
class Seller(models.Model):
"""
You can add this to admin page to make some actions with Seller
"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, on_delete=models.CASCADE, related_name='seller_profile')
# Other properties of Seller
def __str__(self):
return "%s's Seller profile" % self.user
It is not that hard buddy look:
you create a model User
class User(models.Model):
.........
types = (('b','buyer'),('s','seller'))
user_type = models.CharField(max_length=7, choices=types)
so every field has this argument called choices, it is a tuple that has tuples in it, every sub tuple is a choice and every choice has two elements the first one is what appears in the back end and the second element is what appears in the user interface, so 'b' is what appears in the back end and 'buyer' is what the user see in the form in the web site. Tell if that didn't work for you
class Account(models.Model):
types = (
('B', 'BUYER' ),('S', 'SELLER')
)
name = models.Charfield(max_length=15)
username = models.CharField(max_length=15)
email = models.EmailField()
password = models.CharField(max_length=16)
user_type = models.CharField(max_length=12, choices=types)
TRY THIS AND THEN GO TO YOUR ADMIN PAGE AND YOU WILL UNDERSTAND EVERYTHING
I am working on an intranet web application which needs two types of users. Normal users that can be setup from django admin and specific type of users -
Employees.
I have the following model for Employee type user.
class Employee(models.Model):
emp_name = models.CharField(max_length=500)
slug = models.SlugField(unique=True, default='')
location = models.CharField(max_length=200)
email = models.EmailField()
experience = models.TextField(blank=True)
primary_skill = models.ManyToManyField(PrimarySkill)
secondary_skill = models.ManyToManyField(SecondarySkill)
I tried having a OneToOneField like this as per the official doc and
this article:
user = models.OneToOneField(User, blank=True, null=True, on_delete=models.CASCADE)
#receiver(post_save, sender=User)
def create_employee(sender, instance, created, **kwargs):
if created:
Employee.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_employee(sender, instance, **kwargs):
instance.employee.save()
I realized that this is the opposite of what I want. Every time a User
is created from the admin, there was an entry created in the
app_employee table.
What I want is this:
Every time an Employee is created, I need a User created.
An Employee can be created using a separate signup form, say emp_signup
How do I approach this scenario?
I have achieved this using a custom user based on AbstractUser inspired by this article.
class CustomUser(AbstractUser):
pass
class Employee(CustomUser):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
# other fields
In settings.py, I then add the following key:
AUTH_USER_MODEL = 'myapp.CustomUser'
And wherever I need to refer the User class, I use get_user_model(), which will substitute our custom user, in views and forms as follows:
views.py
from django.contrib.auth import get_user_model
def user_profile(request):
User = get_user_model()
user = get_object_or_404(User, username=request.user.username)
return render(request, 'user/user_profile.html', {
'site_user': user
})
forms.py
class SignUpForm(UserCreationForm):
class Meta:
model = get_user_model()
fields = ('username', 'email', 'password1', 'password2',)