I have looked through the similar SOverflow questions and no answer helped.
I am trying to create a follower/following relationship when a button is pressed, passing the info through Javascript...
function follow(user) {
fetch(`/profile/${user.id}`, {
method: 'POST',
body: JSON.stringify({
followed: user.id
})
})
.then(response => response.json())
.then(() => load_profile(user.id))
}
...then I receive it and try to save it or update it...
#csrf_exempt
#login_required
def view_profile(request, user_id):
if request.method == "POST":
data = json.loads(request.body)
followed = data.get("followed", "")
follower = request.user.id
obj, created = UserFollowing.objects.get_or_create(user_id=followed, following_user_id=follower, following=True)
if not created:
obj(following=False)
obj.save()
return JsonResponse({"message": "(Un)Followed successfully."}, status=201)
... and this is the model:
class User(AbstractUser):
pass
def serialize(self):
return {
"id": self.id,
"user": self.username,
"following": self.following.count(),
"followers": self.followers.count(),
}
class UserFollowing(models.Model):
user_id = models.ForeignKey(User, on_delete=models.CASCADE, related_name="following")
following_user_id = models.ForeignKey(User, on_delete=models.CASCADE, related_name="followers")
following = models.BooleanField(blank=False, default=True)
ERROR: ValueError: Cannot assign "3": "UserFollowing.user_id" must be a "User" instance.
I have tried to pass different values such as the username, the object itself, to no avail.
This line:
followed = data.get("followed", "")
If your body message (data) does not contain followed keyword than empty string will be assigned to followed variable otherwise a number.
Both cases would make you trouble later at this line, where followed has to be a user object and can't be an empty string or a number.
obj, created = UserFollowing.objects.get_or_create(user_id=followed, following_user_id=follower, following=True)
You will also get the same error at the following line where you assign a number to the follower variable which, according to your model, has to be a user object as well.
follower = request.user.id
Possible solution to that:
#csrf_exempt
#login_required
def view_profile(request, user_id):
if request.method == "POST":
data = json.loads(request.body)
if "followed" in data:
followed = data["followed"]
try:
user = User.objects.get(id=followed)
except:
# user does not exist
follower = request.user
obj, created = UserFollowing.objects.get_or_create(user_id=user, following_user_id=follower, following=True)
if not created:
obj(following=False)
obj.save()
return JsonResponse({"message": "(Un)Followed successfully."}, status=201)
Related
this is my code for my project, I just get this error I tried to figure it out but I don't get it,
Django Error:
DoesNotExist at /save_post/
Profile matching query does not exist.
views.py, line 75, in save_post
form.authore = Profile.objects.get(user=request.user)
views.py
#login_required
def save_post(request):
if request.method == "POST":
form = Post(content=request.POST['content'])
form.authore = Profile.objects.get(user=request.user)
form.save()
elif request.method == "PUT":
data = json.loads(request.body)
post_id = int(data["post_id"])
new_content = data["new_content"]
post = Post.objects.filter(id=post_id).first()
if post.authore.user != request.user:
return HttpResponse(status=401)
post.content = new_content
post.save()
return JsonResponse({
"result": True
}, status=200)
else:
return JsonResponse({
"error": "post not found"
}, status=400)
return index(request)
models.py
class User(AbstractUser):
pass
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Post(models.Model):
content = models.TextField()
timestamp = models.DateTimeField(default=timezone.now)
authore = models.ForeignKey(Profile, on_delete=models.CASCADE)
likes = models.PositiveIntegerField(default=0, blank=True, null=True)
def serialize(self):
return {
"id": self.id,
"content": self.content,
"timestamp": self.timestamp.strftime("%b %#d %Y, %#I:%M %p"),
"authore": self.authore.id,
"username": self.authore.user.username,
"likes": self.likes.count(),
}
this seems correct but you already this user you are using doesn't have profile
so here my notes :
You can use get_object_or_404 this if profile not found will return not found
from django.shortcuts import get_object_or_404
form.authore = get_object_or_404(Profile, user=request.user)
when user-created no logic here profile must created so it is logical user doesn't have profile
it is better to use one_to_one relation ship when creating user profile as each user has only one profile and vice versa
to make it correct working refer here
https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html
go to Extending User Model Using a One-To-One Link in previous link
field execute this tutorial and user profile will created auto when user created
I am attempting to query Conversation, which has a many to many field called members. I am doing this so that I can then pass Conversation to my InstantMessage object because that object has a foreign key called conversation that attaches to Conversation. I need to check if members are apart of Conversation first, and then if so, get, or if not, create, and then pass that into my InstantMessage object. But for some reason, I am not able to query it and I don't understand why.
error
Exception Value:
Cannot use QuerySet for "Conversation": Use a QuerySet for "Profile".
views.py/message
def message (request, profile_id):
other_user = get_object_or_404(Profile,id=profile_id)
members = Conversation.objects.filter(members= request.user).filter(members= other_user)
conversation, created = Conversation.objects.get_or_create( members = members)
if request.method == 'POST':
form = MessageForm(request.POST, instance= request.user, sender=request.user, conversation = conversation, message=message, date=date)
if form.is_valid():
form.save()
return redirect ('dating_app:messages.html')
else:
conversation, created = Conversation.objects.get_or_create( members= [request.user, other_user])
form = MessageForm(instance= request.user, sender=request.user, conversation= conversation, message=message, date=date)
context = {'form' : form }
return render(request, 'dating_app:messages.html', context)
models.py/Conversatin and InstantMessage
class Conversation(models.Model):
members = models.ManyToManyField(settings.AUTH_USER_MODEL)
class InstantMessage(models.Model):
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name= 'sender',on_delete=models.CASCADE )
conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE)
message = models.TextField()
date = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.message
I created an edit function to edit username of user.
def edit(request):
if request.user.is_authenticated:
data = request.POST
s = UserSerializer(data=data)
u = s.is_valid()
if u:
s.update(request.user.username,request.POST['username'])
return JsonResponse(
{
'message' : 'profile edited!'
},status=201
)
else:
return JsonResponse(
{
'message' : 'you are not login!'
},status=401
)
I don't know where PUT should be used and also how can I use update() .
and this is my serializer class :
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'username','email','password'
)
def validate_password(self,password):
password = make_password(password)
return password
def update(self,isinstance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.email = validated_data.get('email', instance.email)
return instance
in Django rest framework APIView class, you should use from put function instead of edit:
def put(request):
...
to use serializer, in your view function, use serializers.save() function:
def put(request):
....
s.save()
the save function, based on the view function will call update (for put function), create (for post function), and destroy (for delete function).
when you want to instantiate from the serializer class, you must pass the model object as instance and data as data attribute. in summary your view function will be something like this:
class YourView(APIView)
def put(request):
if request.user.is_authenticated:
s = UserSerializer(instance=request.user, data=request.POST)
if s.is_valid():
s.save()
return Response(
{
'message': 'profile edited!'
}, status=201
)
else:
return Response(
{
'message' : 'you are not login!'
},status=401
)
This is probably very simple and basic but I'm struggling with grabbing a newly-created object in Django. It is for a basic library-style app. Over in models, I do this to create a Book object:
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
if not Author.objects.filter(first_name=first_name, last_name=last_name).exists():
author_obj = Author.objects.create(first_name=first_name, last_name=last_name)
else:
author_obj = Author.objects.get(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
Then in views, I call that method and wish to redirect to a page specifically for that newly-created object. I think you can see that I have most of the code down, but don't know what to put in place of the "????".
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
Book.objects.add_book(request.POST, request.session['uid'])
book_id = Book.objects.get(????).id
return redirect('/books/book/{}/'.format(book_id))
else:
context = {
'errors' : errors,
}
1st part use get_or_create for retrieve or create a model entry
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
author_obj, created = Author.objects.get_or_create(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
2nd part, return self.create return a Book entity :
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
book = Book.objects.add_book(request.POST, request.session['uid'])
return redirect('/books/book/{}/'.format(book.id))
else:
context = {
'errors' : errors,
}
There are some issues here. At the very least, look at Django Forms before you go much further. This is what a view that creates an object could look like:
def add_book(request):
if request.POST:
author, created = Author.objects.get_or_create(first_name=first_name,
last_name=last_name)
book = Book(title = request.POST['title'],
user_obj = request.GET['user'],
author = author,)
book.save()
return redirect('/books/book/{}/'.format(book.id))
else:
return render(request, 'book_form.html')
You really need to look into ModelForms to handle your POSTs. But start with looking at Forms.
This is a problem which I've been fighting with for a while and now I gave up. I am writing a User/Profile model in Django 2.0.2 (python 3.6 + postgres 10 on Linux) which is as follows :
class Config_Table(models.Model):
entity_name = models.TextField(primary_key=True)
category = models.TextField()
description = models.TextField(blank=True,default='')
Above table keeps some static information which gets me into trouble.
class UserProfile(AbstractUser):
"The Profile of a user with details are stored in this model."
username = models.TextField(primary_key=True, max_length=11)
first_name = models.TextField(max_length=50,blank=True,default='')
last_name = models.TextField(max_length=100,blank=True,default='')
phone_number = models.TextField(max_length=11,blank=True,default='')
avatar = models.ImageField(blank=True, upload_to='Pictures/')
GENDER_CHOICES = (
('M','Male'),
('F','Female'),
)
gender = models.CharField(max_length=1,choices=GENDER_CHOICES, default='M')
city = models.TextField(max_length=25, blank=True, default='NY')
description = models.TextField(max_length=2000, blank=True, default='')
interests = models.ManyToManyField(Config_Table, blank=True, default='')
date_of_birth = models.DateField(blank=True)
official_docs = models.ImageField(blank=True, upload_to='Pictures/')
team_name = models.TextField(blank=True,default='')
debit_card_number = models.IntegerField(blank=True, default=0)
MUSIC_CHOICES = (
('Rock','Rock Music'),
('Trad','Traditional Music'),
('Elec','Electronic Music'),
('Clas','Classical Music')
)
favorite_music = ArrayField(models.TextField(blank=True,default=''),size=2,blank=True, default='{}')
class Meta:
permissions=(("User","User level permission"),
("Tour","Tourleader level permission"),
("Admin","Administrators"))
my views.py :
class UserList(APIView):
"""
List all users, or create a new user.
"""
def get(self, request, format=None):
users = UserProfile.objects.all()
target_users = []
for user in users.iterator():
if user.is_superuser == False:
target_users.append(user)
serializer = UserProfileSerializer(target_users, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
print(serializer.errors)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserDetail(APIView):
"""
Retrieve, update or delete a User.
"""
pk_url_kwarg = 'username'
def get_object(self, pk):
try:
return UserProfile.objects.get(pk=pk)
except UserProfile.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
user = self.get_object(pk=pk)
if user.is_superuser == False:
serializer = UserProfileSerializer(user)
return Response(serializer.data)
else:
return Response(status=status.HTTP_404_NOT_FOUND)
def put(self, request, pk, format=None):
user = self.get_object(pk)
serializer = UserProfileSerializer(user, data=request.data, partial=True)
if serializer.is_valid():
for attr, value in serializer.validated_data.items():
if attr == 'password' and attr is None:
serializer.validated_data['password'] = user.password
break
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
user= self.get_object(pk)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
and my serializers.py:
def create(self, validated_data):
hashed_password = make_password(validated_data['password']) # get the hashed password
print(validated_data)
user = UserProfile(
username=validated_data['username'],
email = validated_data['email'],
first_name= validated_data['first_name'],
last_name= validated_data['last_name'],
phone_number=validated_data['phone_number'],
avatar=validated_data.pop('avatar'),
gender=validated_data['gender'],
city=validated_data['city'],
description=validated_data['description'],
date_of_birth=validated_data.pop('date_of_birth'),
# user_type=validated_data['user_type'],
official_docs=validated_data.pop('official_docs'),
team_name=validated_data['team_name'],
debit_card_number=validated_data['debit_card_number'],
favorite_music=validated_data['favorite_music'],
)
user.set_password(hashed_password)
interest = validated_data['interests']
user.interests.add(validated_data['interests'])
user.groups.add(validated_data['groups'])
user.save()
return user
The problem I have happens inside the serializer, when I want to submit some JSON object through http, like below (sample data for testing) :
{
"username": "12345678004",
"password": "thisisatest",
"last_login": null,
"is_superuser": false,
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678000",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-03-28",
"team_name": "",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtVo4rjPKrv38gpRtdtzTXiYxLUAAAAAAAAAAAAAAAAAACIzOO670emi3b/unnP2Q9l2M1zVPKOXlaAAAAAAAAA4azTxct+scpUlVMxVieEw9ErNq2MVRVHXn57grwAAAAAAAAAAAAAAAAbW4zciO8x9QXekt7unpj0diOQAAAAAAAAA5aq3vWJj04eXUB5yRtejF2fMtQAAAAAAAAAAAAAAG9n8an/KPq0InE57A9GMUTmiJ7wyAAAAAAAAADFdWKJntAKDUT/Oq8tGa5zXPlgAAAAAAAAAAAAAAAAFxs29vWMdafolqLR39y9E9J4T4XkTmMxxiQZAAAAAAAARNpXd2xjrV9OqVM4jM8IhSay/v3pnpHLwDgAAAAAAAAAAAAAAAAAAnaDWbvs1cuk9kEB6OJ4Cp0F65E4iJqp7f9W0cgAAAAAVevuXJ4TE00+nHPkDX6ze9mn3es90AAAAAAAAAAAAAAAAAAAddPYqrrxH5z0gHOiiaqsRGZWWm2dEca+Pp0S9Pp6aKeEces9ZdQYpiIjEcIZAAAAAAnkAIep0FNWZp9mfkq71mqirEx+kvQNLtqKqcTGQefEjV6Sbc96Z5T9kcAAAAAAAAAAAAAGaKZmqIjnIN9PZmu5iPznsu7FmKLeI/dppNPFu1jrPOXcAAAAAAAAAAAAGK6YmnExmJUut0v8OvvTPKfsu2l63FduYnlIPPje/ami5MT+8NAAAAAAAAAAAFlsvT/wBc/wCv6oFm3vXYiOsr6imKaIiOUA2AAAAAAAAAAAAAAABE2jp9+1mPep+cKd6NSa6zuX57TxgEcAAAAAAAAAFjsm1xmr8o+6ycdJb3dPTHpxdgAAAAAAAAAAAAAAAAEPadresZ60/RMa105omO8A88NrlOLkx2lqAAAAAAA6aejev0x3lzStmU51XiJkFyAAAAAAAAAAAAAAAAAAACl2jRjUz6oyw2vT7VM+ivAAAAAAATdk/jz4AFsAAAAAAAAAAAAAAAAAAACBtb8KPKrAAAAAH/2Q==",
"official_docs": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtVo4rjPKrv38gpRtdtzTXiYxLUAAAAAAAAAAAAAAAAAACIzOO670emi3b/unnP2Q9l2M1zVPKOXlaAAAAAAAAA4azTxct+scpUlVMxVieEw9ErNq2MVRVHXn57grwAAAAAAAAAAAAAAAAbW4zciO8x9QXekt7unpj0diOQAAAAAAAAA5aq3vWJj04eXUB5yRtejF2fMtQAAAAAAAAAAAAAAG9n8an/KPq0InE57A9GMUTmiJ7wyAAAAAAAAADFdWKJntAKDUT/Oq8tGa5zXPlgAAAAAAAAAAAAAAAAFxs29vWMdafolqLR39y9E9J4T4XkTmMxxiQZAAAAAAAARNpXd2xjrV9OqVM4jM8IhSay/v3pnpHLwDgAAAAAAAAAAAAAAAAAAnaDWbvs1cuk9kEB6OJ4Cp0F65E4iJqp7f9W0cgAAAAAVevuXJ4TE00+nHPkDX6ze9mn3es90AAAAAAAAAAAAAAAAAAAddPYqrrxH5z0gHOiiaqsRGZWWm2dEca+Pp0S9Pp6aKeEces9ZdQYpiIjEcIZAAAAAAnkAIep0FNWZp9mfkq71mqirEx+kvQNLtqKqcTGQefEjV6Sbc96Z5T9kcAAAAAAAAAAAAAGaKZmqIjnIN9PZmu5iPznsu7FmKLeI/dppNPFu1jrPOXcAAAAAAAAAAAAGK6YmnExmJUut0v8OvvTPKfsu2l63FduYnlIPPje/ami5MT+8NAAAAAAAAAAAFlsvT/wBc/wCv6oFm3vXYiOsr6imKaIiOUA2AAAAAAAAAAAAAAABE2jp9+1mPep+cKd6NSa6zuX57TxgEcAAAAAAAAAFjsm1xmr8o+6ycdJb3dPTHpxdgAAAAAAAAAAAAAAAAEPadresZ60/RMa105omO8A88NrlOLkx2lqAAAAAAA6aejev0x3lzStmU51XiJkFyAAAAAAAAAAAAAAAAAAACl2jRjUz6oyw2vT7VM+ivAAAAAAATdk/jz4AFsAAAAAAAAAAAAAAAAAAACBtb8KPKrAAAAAH/2Q==",
"debit_card_number": 0,
"favorite_music": [],
"groups": [1],
"user_permissions": [],
"interests": ["Ski"]
}
It always returns TypeError:
user.interests.add(validated_data['interests'])
Exception Type: TypeError at /users/
Exception Value: unhashable type: 'list'
I have tried different ways of implementing "interests" and "groups" in the serializer create function. I tried parsing validated data, selecting the child from Config_table and adding it here, but none of them work.
I actually have the same problem with "groups" field as well. It seems that Django cannot unhash the validated data in serializer and there it throws error.
The interesting point is, if I don't fill in the "group" and "interests" field when calling the POST method, it works fine, and later, I can update those fields by calling PUT with no problem.
What can I do with this?
You should pass to interests.add method different interests objects. Not list of names. So first you need get objects by name and then pass unpacking list of objects to add method using * syntax:
intersts = []
for name in validated_data['interests']:
obj, created = Config_Table.objects.get_or_create(entity_name=name)
interests.append(obj)
user.interests.add(*interests)
OK, I resolved the issue like below :
I changed Config_table model and added default django id field (technically, just removed primary_key from entity_name row, so django added the id AutoField by default). Re-populated the database and changed the code in serializers.py like below..using the answer of #neverwalkaloner :
user = UserProfile(
...
)
user.set_password(hashed_password)
user.save()
interests = []
for id in validated_data['interests']:
interests.append(id)
user.interests.add(*interests)
for name in validated_data['groups']:
user.groups.add(name)
user.save()
return user
Note that I had to save the entity before I wanted to work with a ManyToManyField. As django expects to see something in the database prior to adding some entities for ManyToMany fields. Keep that note in your code.
With this workaround, my problem has been resolved. But it is still strange to me why I could not use a primary key rather than the default. If anyone has an answer to this question, I'm more than willing to hear.