How to Import User and UserProfile data from UserProfile Model Admin? - django

I have this custom User model-
class User(AbstractUser):
email = models.EmailField(unique=True)
picture = models.ImageField(upload_to='profile_picture', null=True, blank=True)
updated_on = models.DateTimeField(auto_now=True)
date_activated = models.DateTimeField(null=True, blank=True)
username = None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
class Meta:
verbose_name = 'User'
and this UserProfile model-
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='userprofile', on_delete=models.PROTECT, primary_key=True)
contact = models.CharField(max_length=20, blank=True, default='')
about_me = models.TextField(null=True, blank=True)
latitude = models.FloatField(validators=[MinValueValidator(-90), MaxValueValidator(90)], null=True, blank=True)
longitude = models.FloatField(validators=[MinValueValidator(-180), MaxValueValidator(180)], null=True, blank=True )
age = models.IntegerField(validators=[MinValueValidator(18), MaxValueValidator(100)], null=True, blank=True )
dob = models.DateField(null=True, blank=True,)
source_of_registration = models.ForeignKey('core.SourceOfRegistration', on_delete=models.PROTECT, null=True,blank=True )
interests = models.ManyToManyField('core.Interest')
languages = models.ManyToManyField('core.SpokenLanguage')
gender = models.ForeignKey('core.Gender', on_delete=models.PROTECT, null=True, blank=True )
country = models.ForeignKey( 'core.Country', on_delete=models.PROTECT, null=True, blank=True )
state = models.ForeignKey('core.State', on_delete=models.PROTECT, null=True, blank=True)
city = models.ForeignKey('core.City', on_delete=models.PROTECT, null=True, blank=True)
zip_code = models.CharField(max_length=12, null=True, blank=True)
is_profile_completed = models.BooleanField(default=False)
profile_completed_on = models.DateTimeField(null=True, blank=True)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = 'User Profile'
def __str__(self):
return self.user.email
def clean(self):
if self.dob:
age_in_days = (datetime.date.today() - self.dob).days
age_in_years = age_in_days / 365
if age_in_years < 18:
raise ValidationError(gettext_lazy('Age should be more or equal to 18.'))
else:
self.age = age_in_years
This is the UserProfileResource-
class UserProfileResource(resources.ModelResource):
class Meta:
model = UserProfile
import_id_fields = (
'user',
'city',
'state',
'country',
'gender',
'source_of_registration',
)
skip_unchanged = True
report_skipped = False
use_bulk= True
fields = (
'user',
'contact',
'about_me',
'longitude',
'latitude',
'age',
'dob',
'zip_code',
'is_profile_completed',
'created_on',
'updated_on',
'city',
'state',
'country',
'gender',
'source_of_registration',
'profile_completed_on',
)
I want to import User data and UserProfile data from one place, UserProfileModelAdmin, i am totally lost now, anyone can give me a hint, how to approach this problem using django_import_export efficiently.
I had also seen this solution, but it is not working for me-
https://github.com/django-import-export/django-import-export/issues/319
Thanks, any kind of hint would be appreciated.

Related

django form is not picking data which is already in database

How do I update my form as the
form.instance.users = request.user
is not working however if I print request.user on terminal it prints the username of the user currently logged in.
Also in this form I want to pick existing data from that user to display in the form to update it.
The save form button return HttpResponse saved successfully but the data is not stored in the database.
models.py
class BasicDetails(models.Model):
GENDERS = (
('M', 'Male'),
('F', 'Female'),
('O', 'Others'),
)
users = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=50, blank=True, null=True)
father_name = models.CharField(max_length=50, blank=True, null=True)
mother_name = models.CharField(max_length=50, blank=True, null=True)
date_of_birth = models.DateField(blank=True, null=True)
gender = models.CharField(max_length=1, choices=GENDERS)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.first_name+" "+ self.last_name
class Education(BasicDetails):
current_year = datetime.date.today().year
YEAR_CHOICES = [(r, r) for r in range(2000, datetime.date.today().year+2)]
course_name = models.CharField(max_length=100, blank=True, null=True)
university_board_name = models.CharField(
max_length=200, blank=True, null=True)
passing_year = models.IntegerField(
choices=YEAR_CHOICES, default=current_year, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(default=timezone.now)
forms.py
class BasicDetailsForm(forms.ModelForm):
class Meta:
model = BasicDetails
fields = '__all__'
exclude = ['users']
class EducationForm(forms.ModelForm):
class Meta:
model = Education
fields = '__all__'
exclude = ['users']
views.py
#login_required
def View(request):
education = EducationForm()
education.instance.users = request.user
if request.method =="POST":
print(request.user.id)
education = EducationForm(request.POST,instance=request.user)
if education.is_valid():
education.save(commit=True)
return HttpResponse("Saved Successfully")
else:
education = EducationForm()
return render(request, 'app/view.html',{'education':education})

Django forms for sex

I am working with a database that stores sex as 0 - male and 1 - female.
My forms.py looks like this
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = TbUser
def clean_username(self):
username = self.cleaned_data["username"]
try:
TbUser.objects.get(username=username)
except TbUser.DoesNotExist:
return username
raise forms.ValidationError(self.error_messages['duplicate_username'])
class TbUserRegisterForm(CustomUserCreationForm):
email = forms.EmailField()
class Meta:
model = TbUser
fields = ['username', 'email', 'cellphone', 'sex', 'role', 'department', 'password1', 'password2']
Django user model
class TbUser(AbstractBaseUser, PermissionsMixin):
id = models.CharField(primary_key=True, max_length=32, default=uuid.uuid4)
username = models.CharField(max_length=40, blank=True, null=True, unique=True, db_column='usname')
password = models.CharField(max_length=255, blank=True, null=True, db_column='dj_psword')
email = models.CharField(max_length=255, blank=True, null=True)
cellphone = models.CharField(max_length=100, blank=True, null=True)
image_id = models.CharField(max_length=40, blank=True, null=True)
sex = models.IntegerField(blank=True, null=True)
is_available = models.IntegerField(blank=True, null=True)
role = models.ForeignKey(TbRole, on_delete=models.CASCADE)
department = models.ForeignKey(TbDepartment, on_delete=models.CASCADE)
is_superuser = models.BooleanField(default=False, blank=True, null=True, db_column='default_super')
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = TbUserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class Meta:
managed = False
db_table = 'tb_user'
def __str__(self):
return '%s' % self.username
Since sex is an integer field, the UI form field is not a choice field but just showing arrows for incrementing the integer. Is there a way to make it a choice field that for m will store 0 and f - 1?
Yes, you can assign this to the choices=… parameter [Django-doc]:
SEX_CHOICES = [
(0, 'Male')
, (1, 'Female')
]
class TbUser(AbstractBaseUser, PermissionsMixin):
# …
sex = models.IntegerField(blank=True, null=True, choices=SEX_CHOICES)
# …

IntegrityError at /job/create/ NOT NULL constraint failed: core_job.category_id

I'm creaating an api that user can create a job. when I want to test it with postman and create a job I have this error:
IntegrityError at /job/create/
NOT NULL constraint failed: core_job.category_id
how do i can fix it ?? I'm using generic CreateAPIView
models:
class Category(models.Model):
name = models.CharField(max_length=300)
slug = models.SlugField(max_length=300, unique=True, help_text='write in English.')
sub_category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.CASCADE)
class Job(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=400, unique=True)
slug = models.SlugField(max_length=400, unique=True, allow_unicode=True)
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING)
image_1 = models.ImageField(upload_to='products_pic/%Y/%m/%d/', null=True, blank=True)
description = models.TextField(null=True, blank=True)
phone1 = models.CharField(max_length=12, null=True, blank=True)
phone2 = models.CharField(max_length=12, null=True, blank=True)
phase = models.CharField(max_length=1, null=True, blank=True)
address = models.TextField(null=True, blank=True)
daily_start_work_time = models.TimeField(null=True, blank=True)
daily_end_work_time = models.TimeField(null=True, blank=True)
create_date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=False)
popular = models.BooleanField(default=False)
views:
class JobCreateView(generics.CreateAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = JobSerializer
queryset = Job.objects.all()
serializers:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
class JobSerializer(serializers.ModelSerializer):
category = serializers.SerializerMethodField()
class Meta:
model = Job
fields = '__all__'
lookup_field = 'slug'
extra_kwargs = {
'url': {'lookup_field': 'slug'}
}
def get_category(self, obj):
return obj.category.name
The category field is not populating with any value when you create the job. I mean category field is Null when you save that form. I am not sure but any way the problem is related to category field

How to update a User and its Profile in nested serializer using generic ListCreateAPIView?

I am working on genericAPIViews in DRF. I am using a built in user model with UserProfile model having one to one relation with it. But I am unable to update user due to nested serializer. My question is that how I can update my built in User model and Profile User model at the same time as UserProfile model is nested in User model.Here is my code:
Models.py
USER_CHOICE = (
('SS', 'SS'),
('SP', 'SP')
)
LOGIN_TYPE = (
('Local', 'Local'),
('Facebook', 'Facebook'),
('Google', 'Google')
)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
cell_phone = models.CharField(max_length=15, blank=True, default="", null=True)
country = models.CharField(max_length=50, blank=True, default="", null=True)
state = models.CharField(max_length=50, blank=True, default="", null=True)
profile_image = models.FileField(upload_to='user_images/', default='', blank=True)
postal_code = models.CharField(max_length=50, blank=True, default="", null=True)
registration_id = models.CharField(max_length=200, null=True, blank=True, default=None)
active = models.BooleanField(default=True)
# roles = models.ForeignKey(Role, null=True, on_delete=models.CASCADE, related_name='role', blank=True)
user_type = models.CharField(max_length=50, choices=USER_CHOICE, null=True, blank=True)
login_type = models.CharField(max_length=40, choices=LOGIN_TYPE, default='local')
reset_pass = models.BooleanField(default=False)
confirmed_email = models.BooleanField(default=False)
remember_me = models.BooleanField(default=False)
reset_code = models.CharField(max_length=200, null=True, blank=True, default="")
reset_code_time = models.DateTimeField(auto_now_add=True, blank=True)
longitude = models.DecimalField(max_digits=80, decimal_places=10, default=0.00)
latitude = models.DecimalField(max_digits=80, decimal_places=10, default=0.00)
r_code = models.CharField(max_length=15, null=True, blank=True)
refer_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="user_refer")
referred = models.ManyToManyField(User, related_name="user_referred", null=True, blank=True)
otp = models.CharField(max_length=6, blank=True, default="", null=True)
def __str__(self):
return self.user.username
Seralizer.py
from rest_framework import serializers
from django.contrib.auth.models import User
from .models import UserProfile
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = '__all__'
class UserSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer()
class Meta:
model = User
fields = ['id', 'username', 'email', 'first_name', 'last_name', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
Views.py
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdminUser]
How can write my .update() methods which can be override according to DRF documentation.Thanks in advance for your addition to my knowledge.
There is update method in ModelSerializer which can be overriden the same way as you did with create.
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile', {})
profile = instance.profile
for attr, value in profile_data.items():
setattr(profile, attr, value)
profile.save()
return super(UserSerializer, self).update(instance, validated_data)
You can also write nested serializer.

How to allow blank field on OneToOne serializer field for Django REST Framework API?

When POSTing to my API endpoint I get a field is required error on a OneToOne field, but I create the OneToOne Field in the save() method of the model I'm POSTing.
I've tried setting default=None, null=True, and blank=True
Device Model
class Device(models.Model):
name = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
brand = models.TextField(max_length=50)
year_purchased = models.IntegerField()
serial_number = models.TextField(max_length=100)
info = models.TextField(max_length=100)
qrcode = models.ImageField(upload_to='', blank=True, null=True)
def save(self, **kwargs):
super(Device, self).save(**kwargs)
if not self.qrcode:
self.generate_qrcode()
if not self.checkouts.exists():
checkout = Checkout(item=self)
checkout.save()
Checkout Model
class Checkout(models.Model):
status_choices = (...)
# Fields
slug = extension_fields.AutoSlugField(populate_from='item', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
due_back = models.DateField(null=True, blank=True)
checked_out = models.DateTimeField(blank=True, null=True)
status = models.CharField(max_length=2, choices=status_choices, default=in_stock)
# Relationship Fields
user = models.OneToOneField(
DeviceUser,
on_delete=models.CASCADE,
related_name="checkouts",
blank=True,
null=True,
default=None,
)
item = models.OneToOneField(
Device,
on_delete=models.CASCADE,
related_name="checkouts",
primary_key=True,
blank=True,
default=None,
)
Device Serializer
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = models.Device
fields = (
'pk',
'name',
'created',
'last_updated',
'brand',
'year_purchased',
'serial_number',
'info',
'checkouts',
)
When POSTing http POST http://localhost:8000/main/api/device/ brand=test2 info=123213123 name=test2 serial_number=12321321 year_purchased=12 'Authorization: Token .....'
I expect to get a confirmation that a device was created, instead I get
"checkouts": [ "This field is required." ]
Specify checkouts field to your DeviceSerializer serializer as,
checkouts = serializers.DateTimeField(default=None, source='checkouts.checked_out', read_only=True)
# code sample
class DeviceSerializer(serializers.ModelSerializer):
checkouts = serializers.DateTimeField(default=None, source='checkouts.checked_out', read_only=True)
class Meta:
model = models.Device
fields = (
'pk',
'name',
'created',
'last_updated',
'brand',
'year_purchased',
'serial_number',
'info',
'checkouts',
)