To begin with, Here Profile and Seller model is created when a User model is created through Signals.What I want to do is When profile model is first created or updated,I want all the fields of Seller model to be same as all fields of Profile.Similarly when I first created Seller model,I also want all fields of Profile Model to be same as that of Seller model.But,I couldn't figure out how to do?
from typing import Tuple
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.db.models.fields import DecimalField
from django.dispatch import receiver
from django.db.models.signals import post_save
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True) #cascade is for deleting the customer
first_name = models.CharField(max_length=10, null=True)
second_name=models.CharField(max_length=10,null=True)
email = models.EmailField(max_length=70, null=True,blank=True)
#receiver(post_save, sender=User)
def create_profile(sender, instance,created,**kwargs):#Signal receivers must accept keyword arguments (**kwargs).
if created:
Profile.objects.create(user=instance)
...
#receiver(post_save, sender=Profile)
def create_seller(sender, instance,created,**kwargs):#Signal receivers must accept keyword arguments (**kwargs).
if created:
Seller.objects.create(user=instance)
class Seller(models.Model):
user = models.OneToOneField(Profile, on_delete=models.CASCADE, null=True, blank=True) #cascade is for deleting the customer
first_name = models.CharField(max_length=10, null=True)
second_name=models.CharField(max_length=10,null=True)
email = models.EmailField(max_length=70, null=True,blank=True)
...
If created=True it means a Profile object is created. otherwise if created=False it means that a Profile object has been updated.
When created=True you need to create a Seller object and when created=False you need to update a Seller object.
You can do this:
#receiver(post_save, sender=Profile)
def update_or_create_seller(sender, instance, created, **kwargs):
if created:
Seller.objects.create(
user=instance.user,
first_name=instance.first_name,
second_name=instance.second_name,
email=instance.email
)
else:
seller = instance.user.seller
seller.first_name = instance.first_name
seller.last_name = instance.second_name
seller.email = instance.email
seller.save()
Also notice that unless you define related_name in your OneToOneField, Django will use lowercased model name to access related object. So, instance.user.seller should work.
Related
I like to bulk import users from xlsx or csv to my original User model. I don't use AbstractUser or AbstractBaseUser and I don't like to because my site is working and I don't want to abuse my schema.
I am using the original User model where I add the users (no user registration allowed) and I store the extra fields in my Profile model with a OneToOne relation.
I'm not so experienced so I tried to use code snippets that I found but I am still not able to achieve my goal. If I try to use import-export module in my admin panel it works with other models but not with the User model. Tablib or other solutions would be also interesting to me.
models.py
(I'm using the original User model that sends a signal to Profile model when a user is created)
class Profile(models.Model):
def __str__(self):
return str(self.user)
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
date = models.DateField(auto_now_add=True, auto_now=False, blank=True)
projekt = models.ForeignKey(Projekt, on_delete=models.CASCADE, default=1)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'last_name', 'first_name', 'password1', 'password2']
admin.py
from django.contrib.auth.models import User
from import_export.admin import ImportExportModelAdmin
#admin.register(User)
class UserAdmin(ImportExportModelAdmin):
pass
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
I got this error message:
django.contrib.admin.sites.AlreadyRegistered: The model User is already registered with 'auth.UserAdmin'.
I understand that my User model is in use but what could I do?
I have a problem to access certain data in my models.
I have a User model giving its id to a Profile model which is giving its id to a ProfileA model.
And when I create a User it automatically creates a Profile.
Here is my user_model
from django.db import models
from django.contrib.auth.models import AbstractUser
from django_countries.fields import CountryField
from .model_custom_user_manager import CustomUserManager
class User(AbstractUser):
"""auth/login-related fields"""
is_a = models.BooleanField('a status', default=False)
is_e = models.BooleanField('e status', default=False)
# objects = CustomUserManager()
def __str__(self):
return "{} {}".format(self.first_name, self.last_name)
My profile_model:
from django.db import models
from django_countries.fields import CountryField
from django.contrib.auth import get_user_model
User = get_user_model()
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
"""non-auth-related/cosmetic fields"""
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
birth_date = models.DateTimeField(auto_now=False, auto_now_add=False, null=True)
nationality = CountryField(null=True)
def __str__(self):
return f'{self.user.username} Profile'
"""receivers to add a Profile for newly created users"""
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
And what I'm trying to do is create a ProfileA when a Profile is created AND when a User has is_a==True.
Here is my profilea_model:
from django.db import models
from .model_profile import *
from django.db.models.signals import post_save
from django.dispatch import receiver
class ProfileA(models.Model):
profile = models.ForeignKey(Profile, null=True, on_delete=models.CASCADE, related_name='profile_a')
biography = models.CharField(max_length=200, null=True)
def __str__(self):
return "{}".format(self.profile)
#receiver(post_save, sender=Profile)
def create_profile_profile_a(sender, instance, created, **kwargs):
if created & Profile.user.is_a == True:
ProfileA.objects.create(profile=instance)
And when I try creating a User with Postman:
{
"username":"Pepe",
"password":"Yolo1234",
"first_name":"Pepe",
"last_name":"Pepito",
"email":"pepe#yolo.com",
"is_a":true,
"is_e":false
}
I get the error:
AttributeError at /users/
'ForwardOneToOneDescriptor' object has no attribute 'is_a'
I've tried a lot of things but nothing woks and using the DjangDocs I can't understand.
What am I doing wrong?
Thanks for your responses!
The instance argument of the create_profile_profile_a function is the instance of Profile which can be easily pointed to User and further get the target attribute is_a.
The receiver part in profilea_model should change to:
#receiver(post_save, sender=Profile)
def create_profile_profile_a(sender, instance, created, **kwargs):
if created & instance.user.is_a == True:
ProfileA.objects.create(profile=instance)
I have a custom user model CustomUser and related models Employee with Foreignkey field to user.
class Employee(models.Model):
"""Employee information."""
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, unique=True)
first_name = models.CharField("first name", max_length=32, blank=True)
last_name = models.CharField("last name", max_length=32, blank=True)
I try to create Employee instance after user registration using post_save signals with fields first_name and last_name imported from my user model fields.
#receiver(post_save, sender=CustomUser)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
if instance.first_name and instance.last_name:
employee = Employee.objects.create(user=instance, first_name=instance.cleaned_data['first_name'], last_name=instance.clened_data['last_name'] )
else:
employee = Employee.objects.create(user=instance)
But always created model with blank field. What is the reason for this and what needs to be changed?
p.s. I need the same filds at both models for some reason.
I am following the tutorials
https://simpleisbetterthancomplex.com/tutorial/2017/02/18/how-to-create-user-sign-up-view.html
on making a simple user registration website.
The key model defined in model.py is
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
which creates the table profile in the database. My question is how do we append this table to include information like user's first/last name and email. I know those information is stored in auth_user, but it would nice to have everything on one table.
I am new to django platform. Any explanation or reference is greatly appreciated.
If you want to append first_name, last name, and email in Profile model then there is no need of this user = models.OneToOneField(User, on_delete=models.CASCADE)
so basically you can remove this line
and
append these field to the model like:
first_name = models.TextField(max_length=50, blank=True)
last_name = models.TextField(max_length=50, blank=True)
email = models.TextField(max_length=200, blank=True)
and run command: python manage.py makemigrations and then
python manage.py migrate
But i will not recomend you to do this.
I suggest you to use django auth user model because then you extra fetures of django very easily like maintaining sessions etc.
follow :- https://docs.djangoproject.com/en/2.0/intro/tutorial01/
I am using Django 1.10.*. This is my user profile model:
class student(models.Model):
user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
state = models.CharField(max_length=21, null=True, blank=True, choices=in_states.STATE_CHOICES)
city = models.CharField(max_length=21, null=True, blank=True)
date_joined = models.DateTimeField(default=timezone.now)
educational_role = models.CharField(max_length=39, choices=EDUCATIONAL_ROLE)
institute = models.ForeignKey(educational_institute, null=True, blank=True)
language = models.CharField(max_length=8, choices=LANGUAGES)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
student.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
When I created form class for student and use that to create a View class extending FormView class in my Views passing the form context to HTML template like this:
forms.py :
class RegistrationForm(forms.ModelForm):
class Meta:
model = student
fields = ['user', 'state', 'city', 'educational_role', 'institute', 'language']
views.py :
class Register(FormView):
template_name = 'searcher/register.html'
form_class = RegistrationForm
def get_context_data(self, **kwargs):
context = super(Register, self).get_context_data(**kwargs)
context['applink'] = applink
context['forumlink'] = forumlink
return context
So how do I need to modify this so that the registration form asks for username, firstname, email of User model and also the fields added by student model and having option for creating a new educational_institute if it doesn't exist already?
You could use multi-table inheritance django.contrib.auth.models.User. Would look like this:
from django.contrib.auth.models import User
class Student(User):
state = models.CharField(...)
...
This way all Django features like ModelForm or UpdateView should function without any additional fiddling. In behind, Django will just create exactly the same OneToOneField for you.
And if all of your users are students you could also replace the auth user model entirely.
If you don't want to do any of those, you will need to add additional fields into your form, specify them if you form Meta, take care of setting their default values (in __init__ in example), cleaning these fields and saving the model behind OneToOneField all by yourself.