Field 'id' expected a number but got <User: ben> - python-3.x

I created a population script for a django website however, after running the script and making migrations, I logged in to the django admin page for my site to access the objects created using the script and could not do it for my Business model. It works fine for my other models.
I get this error when I try to access the registered Businesses in my database from the Django admin page. It does not seem to trace back to any of my code but rather to a template in the admin folder of my python environment. Here's the error message:
error message
Here are my models:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to="profile_images", blank=True, default="profile_images/default.png")
description = models.TextField(max_length=1024, default="")
# boolean flag for identifying business owners
is_business_owner = models.BooleanField(default=False)
def __str__(self):
return self.user.username
class Business(models.Model):
owner_fk = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=128)
address = models.CharField(max_length=128)
img = models.ImageField(upload_to="business_images", blank=True)
slug = models.SlugField(unique=True)
class Meta:
verbose_name_plural = 'Businesses'
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Business, self).save(*args, **kwargs)
def __str__(self):
return f"{self.name} owned by {UserProfile.objects.get(pk=self.owner_fk).username}"
Here is how I created the objects through the population script:
def add_user(username, firstname, lastname, password, profile_pic, description,
is_business_owner):
new_user = User.objects.get_or_create(username=username, password=password,
first_name=firstname, last_name=lastname)
if new_user[1]:
new_profile = UserProfile(user=User.objects.get(username=username))
new_profile.profile_pic = profile_pic
new_profile.description = description
new_profile.is_business_owner = is_business_owner
new_profile.save()
def add_business(owner, name, address, img):
new_business = Business(name=name, owner_fk=User.objects.get(username=owner))
new_business.address = address
new_business.img = img
new_business.save()
Any help would be appreciated, thanks.

Your Business class has got __str__ method. You are trying to pass User object to pk (id) key.
class Business(models.Model):
def __str__(self):
return f"{self.name} owned by {UserProfile.objects.get(pk=self.owner_fk).username}"
Instead of searching User object in database Change it to:
return f"{self.name} owned by {self.owner_fk.username}"
because you don't have to search database for related object, just address it directly.

Related

django UpdateView get_success_url not returning to profile page

I am still new to django and have encountered this issue, the situation is like this, I have a profile model, on which I have 2 views ViewProfile and EditProfile inheriting from DetailView and UpdateView respectively. when I edit the profile page, it doesn't get me to the profile page instead it gave the error:
Reverse for 'profile' with keyword arguments '{'id': 9}' not found. 1 pattern(s) tried: ['profile/(?P<pk>[^/]+)/\\Z']
even though I have checked in the python shell, the profile with id:9 is indeed profile with name muham see below
>>> Profile.objects.all()
<QuerySet [<Profile: huzaifa>, <Profile: another1>, <Profile: muham>]>
>>> p1 = Profile.objects.get(name='muham')
>>> p1.id
9
>>>
but still its not showing,
I have overridden the get_success_url to get me to the profile page:
class EditProfile(LoginRequiredMixin, UpdateView):
model = Profile
fields = ('name', 'address', 'phone_no',)
template_name = 'blog_app/edit_profile.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user'] = self.request.user
return context
def get_success_url(self):
id = self.request.user.profile.id
return reverse_lazy('profile', kwargs={'id': id})
my model is below:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=60, blank=True, null=True)
address = models.CharField(max_length=400, null=True, blank=True)
# image
phone_no = models.CharField(max_length=40, null=True, blank=True)
def __str__(self):
return str(self.user)
class ViewProfile(LoginRequiredMixin, DetailView):
model = Profile
template_name = 'blog_app/profile.html'
context_object_name = 'profile'
urls.py:
urlpatterns = [
path('', ListBlog.as_view(), name='home'),
path('my-blogs/', MyBlog.as_view(), name='my-blogs'),
path('create-blog/', CreateBlog.as_view(), name='blog-create'),
path('blog-detail/<int:pk>/', BlogDetail.as_view(), name='blog-detail'),
path('edit-blog/<int:pk>/', EditBlog.as_view(), name='blog-edit'),
path('delete-blog/<int:pk>/', DeleteBlog.as_view(), name='blog-delete'),
path('profile/<str:pk>/', ViewProfile.as_view(), name='profile'),
path('edit-profile/<str:pk>/', EditProfile.as_view(), name='edit-profile'),
]
I have found my error, it was because DetailView uses pk or slug, on the urlconf arguments, and before i have added str:id instead of str:pk, and also in the
def get_success_url(self):
id = self.request.user.profile.id
return reverse_lazy('profile', kwargs={'id': id})
i had kwargs={'id':id} instead of {"pk": id}. so that was my issue, and it was resolved after that.

Custom User Model with multiple Unique id - Django RestFramework

Hi StackOverFlow buddies,
I have created a custom User model for my project and would like to register the Users with Restframework.
I want Custom User model to have 2 unique fields together, for which I followed "Official doc" for unique_together property. It seems to be only taking only 1 field (ie email for my case), as a unique one.
Relevant piece my code until this point looks like this:
PS: Let me know if more info is required.
models.py
class MasterUser(AbstractBaseUser):
email = models.EmailField(verbose_name='email address',max_length=255,unique=True,)
firstname = models.CharField(max_length=100,blank=True)
contact = models.CharField(max_length=100, blank=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['firstname']
class Meta:
unique_together = (('email', 'contact'),)
serializer.py
class RegisterUserSerializer(serializers.ModelSerializer):
password2 = serializers.CharField(style={'input_type': 'password'}, write_only= True)
class Meta:
model = MasterUser
fields = ('firstname', 'password', 'password2', 'email','contact')
extra_kwargs = {
'password': {'write_only': True},
}
def save(self):
account = MasterUser(
email = self.validated_data['email'],
firstname = self.validated_data['firstname'],
contact = self.validated_data['contact'],
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializers.ValidationError({'password': 'Password doesnt matches'})
account.set_password(password)
account.save()
return account
views.py
#api_view(['POST'])
def registration_view(request):
if request.method == "POST":
serializer = RegisterUserSerializer(data= request.data)
data = {}
if serializer.is_valid():
account = serializer.save()
data['response'] = "Successfully registered new user!"
else:
data = serializer.errors
return Response(data)
Where am I missing to implement thing?
unique_together means the set of fields you defined should be unique for all Users. If you also want contact to be a unique field when stored in db, you should pass the unique parameter like so:
class MasterUser(AbstractBaseUser):
...
contact = models.CharField(max_length=100, blank=True, unique=True)
...

Django login/register issue

I am new to Django and am building a database-driven website using PyCharm.
I am having an issue with users registering/logging in. What is happening is, when a user registers, I check the "Database" tab to the right, and the information will be passed into a table named "SavBlock_user", which will have the users name, password, etc.. Then, when I try to log in, it won't allow me to login due to incorrect username/password. However, if I try to login using a username/password from a different table named "auth_user" (like username: admin / password: admin), then I can successfully login. I'm not sure how to fix this.
Ideally, what I would like to do is completely remove the "SavBlock_user" table and strictly use "auth_user" for all of my users, but I'm not sure how to do this. I may have created a 'custom' user model back when I was learning the system, but I can't remember.
My files:
Project\register\forms.py
from django import forms
from SavBlock.models import * # <--- Contains User
''' Form for users to register '''
class RegisterForm(forms.ModelForm):
email = forms.EmailField(
initial='myemail#savagez.com'
)
uso_validate = forms.BooleanField(
label='Are you a PSMC member? (Chief, Uso, Anak)',
initial=False
)
class Meta:
model = User
widgets = {
'password': forms.PasswordInput(),
}
fields = '__all__'
Project\register\views.py
from django.http import request
from django.shortcuts import render, redirect
from .forms import RegisterForm
# Create your views here.
def register(response):
if response.method == "POST":
form = RegisterForm(response.POST or None)
if form.is_valid():
form.save()
return redirect('/dashboard/')
else:
form = RegisterForm()
return render(response, 'register/register.html', {'form': form})
Project\SavBlock\models.py
from django.db import models
class User(models.Model):
username = models.CharField("user name", max_length=50, default='')
email = models.EmailField("email address", unique=True, default='DEFAULT VALUE')
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
password = models.CharField("password", unique=True, max_length=50, default='')
rank = {
0: 'Supporter',
1: 'Anak',
2: 'Uso',
3: 'Chief'
}
#TODO: FIT __INIT__
'''
def __init__(self, first_name, last_name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.first_name = first_name.title()
self.last_name = last_name.title()
'''
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
#property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[1]
class Uso(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[2]
----EDIT----
I fixed the different user tables and basically reset the migrations. Now, all users are showing up under a single user table SavBlock_user. However, the login issue is still there.
Admin was created using the terminal manage.py createsuperuser command. I am able to login on the webpage using this account.
testing123 was created using the registration form. It pulls up a message that says "Please enter a correct username and password".
Anyone have any ideas?

How to join two tables in django and serialize the same using one serializer?

I have been learning django and django rest framework since couple of weeks and I want to figure out how can I join two tables and serialize the data of same to return the json response using django rest framework.
I want to return result as json response:
{ 'user_id_id': 1, 'request_msg': 'Hi', 'response_msg': "Hi, Welcome" }
where result is
from django.db import connection
cursor = connection.cursor()
con = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
Here is what I have tried :
#backend/Models.py
class User(models.Model):
username = models.CharField(max_length=50)
name = models.CharField(max_length=50, blank=True, null=True)
uid = models.CharField(max_length=12, blank=True, null=True)
age = models.CharField(max_length=3, blank=True, null=True)
active = models.BooleanField(default=True)
class Meta:
default_related_name = 'users'
def __str__(self):
return self.name
class Request_Messages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class Response_Messages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'response_messages'
def __str__(self):
return self.response_msg
#backend/serializers.py
class ListSerializer (serializers.Serializer):
user_id_id = serializers.IntegerField()
request_msg = serializers.CharField(max_length=100)
# request_msg_created_at = serializers.DateTimeField(read_only=True)
response_msg = serializers.CharField()
# response_msg_created_at = serializers.DateTimeField(read_only=True)
#backend/views.py
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Response_Messages, Request_Messages, User
from .serializers import ListSerializer
from django.db import connection
#api_view(['GET', 'POST'])
def chatbot(request):
if request.method == 'GET':
cursor = connection.cursor()
query_set = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
columns = [column[0] for column in query_set.description]
results = []
for row in query_set.fetchall():
results.append(dict(zip(columns, row)))
serializer = ListSerializer(results)
return Response(serializer.data)
About serializers, You should refer to the docs (they're awesome and explain it best).
To give you a direction, I like to create a serializer for every model and if it's related to another model, I refer that in serializer, that way, You can easily customize behavior for each model (although not the only way at all).
So, about serializing I would do the following (notice my comments as well):
from django.contrib.auth.models import User
class User(User):
# Your user class, except, it should inherit Django's User/AbstractUser class.
class RequestMessages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
User, on_delete=models.CASCADE, null=True, related_name='requests_msg')
# NOTICE THE NEW RELATED NAME, WE'LL USE IT LATER.
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class ResponseMessages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='responses_msg')
def __str__(self):
return self.response_msg
class RequestMsgSerializer(serializers.ModelSerializer):
# Specify what ever you like...
class Meta:
model = RequestMessages
fields = # Whatever you like to serialize.
class ResponseMsgSerializer(serializers.ModelSerializer):
class Meta:
model = ResponseMessages
fields = # Whatever you want serialized.
class UserSerializer(serializers.ModelSerializer):
# Using required = False will cause that every time you create a user they don't have to own messages.
requests_msg = RequestMsgSerializer(many=False, required=False)
responses_msg = ResponseMsgSerializer(many=False, required=False)
class Meta:
model = User
field = # Same as above ..
About your query, using raw SQL in Django is rear, usually, in most cases the Django built-in ORM will do the job and usually faster and better than you.
In your case, if you'll call your query like this for exmaple:
query_set = User.objects.filter(user=request.user)
the QuerySet object created will hit the DB one for the user object and X queries for all the associated messages with said user, so expensive.
But no need for a custom query with joins and stuff like that, Django has prefetch_related and select_related.
exmaple:
query_set = User.objects.filter(user=request.user).prefetch_related('requests_msg')
will reduce all the queries made for request messages associated to a user to only one!
Recap:
I wrote a lot because I'm still learning this stuff myself self and if you teach others you got it!
Refer to DRF's docs about serializers (there's even a dedicated section for nested serializers) and API Views, they really great.
Refer to Django's docs about prefetch related, select related and queries in general, again, Amazing docs that cover everything.
Don't just copy my code or anyone else's, there's no problem with that, just make sure you understand it first if not, you're bound to get stuck with it again!

Adding comment feature in Django DetailView?

What the simplest logic i can add in class HotelDetailView(DetailView) so users can comment on a particular hotel detail page. And it capture user too.
models.py
class Hotel(models.Model):
name = models.CharField(max_length=150)
owner = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
image = models.ImageField(upload_to=upload_location, null=True, blank=True)
class CommentOnHotel(models.Model):
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField(max_length=200)
published = models.DateField(auto_now_add=True)
def __str__(self):
return '{} - {}'.format(self.hotel.name, self.user.email)
Forms.py
class CommentOnHotelForm(forms.ModelForm):
class Meta:
model = CommentOnHotel
fields = ['content']
views.py
class HotelDetailView(DetailView):
model = Hotel
........
actually i gave you the better approach for that, but if you want to make all logic and functions at DetailView which is not recommended, here is the solution, you need to override POST function of DetaiView:
class HotelDetailView(DetailView):
model = Hotel
def post(self, request, *args, **kwargs):
# get the hotel object
hotel = self.get_object()
#check for validation of form
form = CommentOnHotelForm({
"hotel": hotel,
"user" :request.user
"comment": request.POST.comment
})
if form.is_valid():
form.save()
#choose where you want to redirect

Resources