'Account' object has no attribute 'products' AND (fields.E301) Field defines a relation with the model 'auth.User', which has been swapped out.' - django-models

I am following Django rest_framework tutorial to build my app but and I'm using a custom user model (Account) which inherits AbstractBaseUser.
I have another model - Product - and each product is owned by an Account.
My models.py is:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.conf import settings
class Product(models.Model):
owner = models.ForeignKey(Account, related_name='account', on_delete=models.CASCADE, default=1)
name = models.CharField(max_length=71)
product = models.CharField(max_length=20, blank=True)
price = models.IntegerField(null=True, blank=True)
quantity = models.IntegerField(default=0)
image = models.ImageField(upload_to='images', blank=True)
display = models.BooleanField(default=False)
created = models.DateTimeField('date added', auto_now=True)
modified = models.DateTimeField('date modified', auto_now_add=True)
def __str__(self):
return self.name
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, password=None):
if not email:
raise ValueError("Please enter a valid email address")
if not username:
raise ValueError("Please enter a username")
user = self.model(
email = self.normalize_email(email),
username = username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(
email = self.normalize_email(email),
password = password,
username = username,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last_login', auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_merchant = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
My settings.py includes:
AUTH_USER_MODEL = 'accounts.Account'
My serializers.py is:
from rest_framework import serializers
from inventory.models import Product
from accounts.models import Account
class AccountSerializer(serializers.ModelSerializer):
products = serializers.PrimaryKeyRelatedField(many=True, queryset=Product.objects.all())
password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = Account
fields = ['products', 'email', 'username', 'password', 'password2']
extra_kwargs = {
'password': {'write_only': True}
}
def save(self):
account = Account(
email = self.validated_data['email'],
username = self.validated_data['username'],
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializers.ValidationError({'password': 'Passwordss must match.'})
account.set_password(password)
account.save()
return account
class ProductSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.email')
class Meta:
model = Product
fields = [
'id', 'owner', 'name', 'product', 'price', 'quantity', 'image', 'display'
]
My views.py is:
from accounts.api.serializers import AccountSerializer
from inventory.api.serializers import ProductSerializer
from inventory.models import Product
from accounts.models import Account
from rest_framework import permissions
from rest_framework import generics
class AccountList(generics.ListAPIView):
queryset = Account.objects.all()
serializer_class = AccountSerializer
class AccountDetail(generics.RetrieveAPIView):
queryset = Account.objects.all()
serializer_class = AccountSerializer
class ProductList(generics.ListCreateAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Product.objects.all()
serializer_class = ProductSerializer
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class ProductDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Product.objects.all()
serializer_class = ProductSerializer
I am able to view my ProductList and ProductDetail however, I get the following error when I try to view AccountList and AccountDetail:
**Exception Type:** AttributeError
**Exception Value:** 'Account' object has no attribute 'products'

Just change your serailzier like this
class AccountSerializer(serializers.ModelSerializer):
products = serializers.SerializerMethodField()
password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True)
def get_products(self, instance):
return Product.objects.all().values_list('id', flat=True)
class Meta:
model = Account
fields = ['products', 'email', 'username', 'password', 'password2']
extra_kwargs = {
'password': {'write_only': True}
}
def save(self):
account = Account(
email = self.validated_data['email'],
username = self.validated_data['username'],
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializers.ValidationError({'password': 'Passwordss must match.'})
account.set_password(password)
account.save()
return account
PrimaryKeyRelatedField may be used to represent the target of the relationship using its primary key. The queryset used for model instance lookups when validating the field input. Your field is read_only field. Your should use SerializerMethodField for this.

Related

I am getting null value in column "user_id" violates not-null constraint, how can I get foreign key data to register on my comment form?

This my models.py file
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
class UserAccountManager(BaseUserManager):
def create_user(self, name, email, password, **other_fields):
if not email:
raise ValueError('Users must have an email adress')
email = self.normalize_email(email)
user = self.model(name=name, email=email, password=password)
user.set_password(password)
user.save()
return user
def create_superuser(self, name, email, password = None, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
return self.create_user(name=name, email=email, password = password, is_superuser=True)
class UserAccount(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=355, unique=False)
is_superuser = models.BooleanField(default=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=True)
objects = UserAccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def __str__(self):
return str(self.id)
I have a foreign key on my comment model, I tested this on django admin and it works fine, but with my comment form, the foreign key isn't populating, i just get "null value in column "user_id" violates not-null constraint", I dont know what im doing wrong
class Comment(models.Model):
comment = models.CharField(max_length=250)
user = models.ForeignKey(UserAccount, on_delete=models.CASCADE)
def __str__(self):
return str(self.user.id)
serializers.py
from djoser.serializers import UserCreateSerializer
from django.contrib.auth import get_user_model
from rest_framework.serializers import ModelSerializer
from accounts.models import Comment
User = get_user_model()
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ('id', 'name', 'email', 'password')
I am reffering my foreign key user as a field, i'm not sure if that is correct.
class CommentSerializer(ModelSerializer):
class Meta:
model = Comment
fields=('id', 'comment', 'user')
viewsets.py
from rest_framework import viewsets
from . import models
from . import serializers
class CommentViewset(viewsets.ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = serializers.CommentSerializer
router.py
from accounts.viewsets import CommentViewset
from rest_framework import routers
router = routers.DefaultRouter()
router.register('comment', CommentViewset)
You need to add user_id field for writing in the serializer.
class CommentSerializer(ModelSerializer):
class Meta:
model = Comment
fields=('id', 'comment', 'user')
extra_kwargs = {
'user': { 'read_only': True }
}
def create(self, validated_data):
new_comment = Comment(**validated_data)
new_comment.user_id = self.context['request'].user.id
new_comment.save()
return new_comment

__str__ returned non-string (type Category). when I add post from admin

After I added user and date_added in the Photo models, when I add post from admin its throws me an error saying: str returned non-string (type Category), when I click on the addpost link in the home template its throw another error: 'tuple' object has no attribute 'name'. how can I solve that ?
the models.py:
from django.db import models
from cloudinary.models import CloudinaryField
from django.contrib.auth.models import User
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return self.name
class Photo(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True,
blank=True)
image = CloudinaryField('image')
description = models.TextField(null=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.category
the view.py file:
def home(request):
category = request.GET.get('category')
if category == None:
photos = Photo.objects.all()
else:
photos = Photo.objects.filter(category__name=category)
categories = Category.objects.all()
context = {'categories': categories, 'photos': photos}
return render(request, 'home.html', {'categories': categories, 'photos': photos} )
def viewPhoto(request, pk):
photo = Photo.objects.get(id=pk)
return render(request, 'photo.html', {'phpto': photo})
class PostCreativeView(LoginRequiredMixin, CreateView):
model = Photo, Category
fields = ['description', 'image', 'category', 'name']
template_name = 'post_create.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super (PostCreativeView, self).form_valid(form)
Well it has to do with your category name and model you added into post create view.py and so you
have do something like this:
views.py
class PostCreativeView(LoginRequiredMixin, CreateView):
model = Photo
fields = ['description', 'image', 'category']
template_name = 'post_create.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super (PostCreativeView, self).form_valid(form)
#.......
# Models.py
class Photo(models.Model):
#>>>...
def __str__(self):
return str(self.category)
You should return the str(…) of the category, so:
class Photo(models.Model):
# …
def __str__(self):
return str(self.category)

Identify the custom user model in REST_FRAMEWORK settings Django

I'm new in Django rest_framework. I'm using a custom user model and djoser as my authentication system. I want to use my custom user model in the djoser register view and I don't know how to identify that in the rest_framework settings?
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSIONS_CLASSES':(
'rest_framework.permissions.IsAuthenticated',
),
}
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, phone, password=None):
if not email:
raise ValueError("Users must have an email address")
if not username:
raise ValueError("Users must have an username")
if not phone:
raise ValueError("Users must have a phone number")
user = self.model(
email=self.normalize_email(email),
username=username,
phone=phone
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,email, username, phone, password):
user = self.create_user(
email=self.normalize_email(email),
username=username,
phone=phone,
password=password
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email",max_length=60, unique=True)
username = models.CharField(max_length=60,unique=True)
phone = models.CharField(max_length=60,unique=True)
date_joined = models.DateTimeField(verbose_name="date joined",auto_now_add=True)
last_login = models.DateTimeField(verbose_name="last login",auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
first_name = models.CharField(max_length=60,null=True)
last_name = models.CharField(max_length=60,null=True)
wilaya = models.CharField(max_length=60,null=True)
city = models.CharField(max_length=60,null=True)
address = models.CharField(max_length=200,null=True)
store_coordinates = models.CharField(max_length=60,null=True)
documents1 = models.CharField(max_length=60,null=True)
documents2 = models.CharField(max_length=60,null=True)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email','phone']
objects = MyAccountManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
What should I add to use my custom user model in djoser register view?
You're doing almost everything right, but you need to tell Django in the settings what user model it should use.
In models.py use something like this
from django.contrib.auth.models import AbstractUser
from .managers import UserManager
class User(AbstractUser):
# Add whatever fields you want
# Use your custom manager
objects = UserManager()
In settings.py
# Tell Django what user model should be used
AUTH_USER_MODEL = 'auth.User' # app_label.model
make sure you use python manage.py makemigrations && python manage.py migrate to create your custom user model.
Enjoy!

How can I access my models in django admin?

I am working on an AlumniTracker in django and till now I have created forms for user sign up and some additional information.
Even after saving the additional information form I am not able to access it in django-admin.
I am adding my models, views and forms file here.
views.py
def student_profile(request):
if request.method == 'POST':
form = StudentDetailForm(request.POST)
if form.is_valid:
student_form = form.save(commit=False)
student_form.user = request.user
student_form.save()
return redirect(reverse('homepage'))
else:
form = StudentDetailForm()
return render(request, 'authentication/student_profile.html', {'form':form})
def alumni_profile(request):
if request.method == 'POST':
form = AlumniDetailForm(request.POST)
if form.is_valid:
alumni_form = form.save(commit=False)
alumni_form.user = request.user
alumni_form.save()
return redirect(reverse('homepage'))
else:
form = AlumniDetailForm()
return render(request, 'authentication/student_profile.html', {'form':form})
forms.py
class StudentDetailForm(ModelForm):
class Meta:
model = StudentDetail
fields = ['first_name', 'last_name', 'contact_no', 'birth_date', 'course', 'session_start', 'session_end']
class AlumniDetailForm(ModelForm):
class Meta:
model = AlumniDetail
exclude = ['user']
models.py
class CustomUser(AbstractUser):
profile = models.CharField(max_length=10,choices=PROFILE_CHOICES, default='student')
def __str__(self):
return self.username
class StudentDetail(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
contact_no = models.IntegerField()
birth_date = models.DateField()
course = models.CharField(max_length=50)
session_start = models.IntegerField()
session_end = models.IntegerField()
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class AlumniDetail(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
contact_no = models.IntegerField()
birth_date = models.DateField()
course = models.CharField(max_length=50)
session_start = models.IntegerField()
session_end = models.IntegerField()
company = models.CharField(max_length=60)
open and edit admin.py
and register your models by adding code below admin import
from .models import CustomUser,StudentDetail,AlumniDetail
admin.site.register(CustomUser)
admin.site.register(StudentDetail)
admin.site.register(AlumniDetail)

How to add custom user field (phone_number) in django default user table?

I need to add a custom field called phone_number to the default django user table
Everything work fine but the phone_number field and value does not save in Table Django User.
Here is my custom form code
class SignUpForm(UserCreationForm):
username = forms.EmailField(label="Email Address", max_length=254, help_text='Required a valid email address.')
phone_number = forms.CharField(max_length=30, help_text='Required.')
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'phone_number', 'password1', 'password2')
Here is my view code for user registration
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
mail_subject = 'Activate Your Account.'
message = render_to_string('app/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('username')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return render(request, 'app/account_confirm_message.html')
else:
form = SignUpForm()
return render(request, 'app/signup.html', {'form': form})
My Model is here
class Profile(models.Model):
STUDENT = 1
TEACHER = 2
ROLE_CHOICES = (
(STUDENT, 'Student'),
(TEACHER, 'Teacher'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
email_confirmed = models.BooleanField(default=False)
role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True)
# this method called for admin panel
class Meta:
verbose_name = 'profile'
verbose_name_plural = 'profiles'
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()

Resources