I am doing a group project for a bootcamp and we just started Django for the back-end. We also are using React for front-end. Our project is basically a knockoff reddit.
We have a User model:
`from django.db import models
class User(models.Model):
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
email = models.CharField(max_length=100, unique=True)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=255)
def __str__(self):
return '%s' % (self.username)`
and a Post model:
`from django.db import models
from auth_api.models import User
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=255)
formBody = models.TextField(null=True, blank=True)
imageURL = models.CharField(max_length=200, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)`
Our Post Serializers(pretty unfamiliar with this):
`from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
user = serializers.CharField(required=True)
class Meta:
model = Post
fields = ('id', 'user', 'title', 'formBody', 'imageURL', 'created',)`
And our Post Views:
`from django.shortcuts import render
from rest_framework import generics
from .serializers import PostSerializer
from .models import Post
from auth_api.models import User
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all().order_by('id')
serializer_class = PostSerializer
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all().order_by('id')
serializer_class = PostSerializer`
The idea was when a user created a post their info would be saved with the post so that way when we display the post we could say who created at. Also we could have a user profile that could see all of their posts. I assumed that what would happen is the user info would get saved inside a object in the user column, but the first way we tried only saved the userID and we couldn't access any of the users info. The second way(what we have now) keeps giving us this error: ValueError: Cannot assign "'1'": "Post.user" must be a "User" instance.The 1 is the userID that we pass in from the frontend of the user that created the post. I am unsure of where to go from here and have been stuck for a while on this. Hopefully I provided enough info
I'm trying to get the user data from Customer model. For this I also connect the Customer to User which I import from django.contrib.auth.models. But getting this error:
AttributeError at /user/
'User' object has no attribute 'Customer'
at views page:
#login_required(login_url='login')
def user_page(request):
orders=request.user.Customer.order_set.all()
context={'orders':orders}
return render(request, 'blog/user_page.html', context)
at models page
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
User=models.OneToOneField(User, null=True, on_delete=models.CASCADE)
name=models.CharField(max_length=200, null=True)
email=models.EmailField()
phone=models.IntegerField(null=True)
date_created=models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.name
you can change it as follows
orders=Customer.objects.filter(user=request.user)
change the user to lower case in model fields
user=models.OneToOneField(User, null=True, on_delete=models.CASCADE)
Well, I have a VagasUsuarios model and a Questionario model. I would like that when I updated the Questionario.pontuacao_questionario field via django admin, my other VagaUsuarios.pontuacao_vaga field would be updated as well. Is there a way to do this?
thanks for listening =)
My Models:
class Questionario(models.Model):
usuario = models.ForeignKey(Contas, on_delete=models.CASCADE)
[...]
pontuacao_questionario = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True,verbose_name="Pontuacao do Questionário")
class VagasUsuarios(models.Model):
usuario = models.ForeignKey(Contas, on_delete=models.CASCADE)
[...]
pontuacao_vaga = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="Pontuacao da Vaga")
You could do this with signals.
Example:
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import Questionario, VagasUsuarios
#receiver(post_save, sender=Questionario)
def my_handler(sender, instance, **kwargs):
obj = VagasUsuarios.objects.get(...)
obj.pontuacao_vaga = instance.pontuacao_questionario
obj.save()
Another is to override the save() (or rather clean()) method of your model and when it gets updated to fetch all the relevant VagasUsuarios-objects you want to update and update them.
Note on clean(): You got to call the clean-method yourself unless you are using the Django admin.
I want to create Profile extending User model.
from django.db import models
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
operatorId = models.CharField(
max_length=50,
default= 'O'+str(user.id), #get user id
blank=False,
unique=True,
)
Want to add operatorId which depends on userId chosen (operator id i O and user.id as a string). How to get current user id? basically, I need to change default every-time I change user. Is it possible?
you should override save method
from django.db import models
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
operatorId = models.CharField(
max_length=50,
blank=False,
unique=True,
)
def save(self, *args, **kwargs):
self.operatorId = 'O'+str(self.user.id) # set operatorId here
super().save(*args, **kwargs)
note that overriding save has a limitation:
Unfortunately, there isn’t a workaround when creating or updating
objects in bulk, since none of save(), pre_save, and post_save are
called.
check django docs for more info
I have a Django model and I want to modify the object permissions on or just after save. I have tried a few solutions and the post_save signal seemed the best candidate for what I want to do:
class Project(models.Model):
title = models.CharField(max_length=755, default='default')
assigned_to = models.ManyToManyField(
User, default=None, blank=True, null=True
)
created_by = models.ForeignKey(
User,
related_name="%(app_label)s_%(class)s_related"
)
#receiver(post_save, sender=Project)
def assign_project_perms(sender, instance, **kwargs):
print("instance title: "+str(instance.title))
print("instance assigned_to: "+str(instance.assigned_to.all()))
In this case, when a Project is created, the signal fires and I see the title, but an empty list for the assigned_to field.
How can I access the saved assigned_to data following save?
You're not going to. M2Ms are saved after instances are saved and thus there won't be any record at all of the m2m updates. Further issues (even if you solve that) are that you're still in a transaction and querying the DB won't get you m2m with proper states anyways.
The solution is to hook into the m2m_changed signal instead of post_save.
https://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed
Your sender then would be Project.assigned_to.through
If your m2m can be empty (blank=True) you are in a little trouble with m2m_changed, because m2m_changed doesn't fire if m2m wasn't set. You can solve this issue by using post_save and m2m_changed at the same time. But there is one big disadvantage with this method - your code will be executed twice if m2m field isn't empty.
So, you can use transaction's on_commit (Django 1.9+)
Django provides the on_commit() function to register callback
functions that should be executed after a transaction is successfully
committed.
from django.db import transaction
def on_transaction_commit(func):
def inner(*args, **kwargs):
transaction.on_commit(lambda: func(*args, **kwargs))
return inner
#receiver(post_save, sender=SomeModel)
#on_transaction_commit
def my_ultimate_func(sender, **kwargs):
# Do things here
Important note: this approach works only if your code calls save().
post_save signal doesn't fire at all in cases when you call only instance.m2m.add() or instance.m2m.set().
Use transaction on commit!
from django.db import transaction
#receiver(post_save, sender=Project)
def assign_project_perms(sender, instance, **kwargs):
transaction.on_commit(lambda: print("instance assigned_to: "+str(instance.assigned_to.all())))
here is an example about how to use signal with many to many field (post like and post comments models),
and in my example i have :
like model (Intermediary table for User and Post tables) : the user can add 1 record only in Intermediary table for each post , which means (unique_together = ['user_like', 'post_like']) for this type of many to many relations you can use 'm2m_changed' signals ,
comment model (Intermediary table for User and Post tables): the user can add many records in Intermediary table for each post , (without unique_together ), for this i just use 'post_save, post_delete' signals , but you can use also 'pre_save, pre_delete' if you like ,
and here is both usage example :
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save, post_delete, m2m_changed
from django.dispatch import receiver
class Post(models.Model):
post_user = models.ForeignKey(User,related_name='post_user_related', on_delete=models.CASCADE)
post_title = models.CharField(max_length=100)
post_description = models.TextField()
post_image = models.ImageField(upload_to='post_dir', null=True, blank=True)
post_created_date = models.DateTimeField(auto_now_add=True)
post_updated_date = models.DateTimeField(auto_now=True)
post_comments = models.ManyToManyField(
User,
through="Comments",
related_name="post_comments"
)
p_like = models.ManyToManyField(
User, blank=True,
through="LikeIntermediary",
related_name="post_like_rel"
)
class LikeIntermediary(models.Model):
user_like = models.ForeignKey(User ,related_name="related_user_like", on_delete=models.CASCADE)
post_like = models.ForeignKey(Post ,related_name="related_post_like", on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user_like} - {self.post_like} "
class Meta:
unique_together = ['user_like', 'post_like']
#receiver(m2m_changed, sender=LikeIntermediary)
def like_updated_channels(sender, instance, **kwargs):
print('this m2m_changed receiver is called, the instance is post id', instance.id)
class Comments(models.Model):
cmt_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="related_comments_user")
cmt_post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="related_comments_post")
cmt_created_date = models.DateTimeField(auto_now_add=True)
cmt_comment_body = models.TextField()
cmt_created = models.DateTimeField(auto_now_add=True)
cmt_updated = models.DateTimeField(auto_now=True)
#receiver(post_save, sender=Comments)
def comments_updated_channels(sender, instance, created, **kwargs):
print('this post_save receiver is called, the instance post id', instance.cmt_post.id)
#receiver(post_delete, sender=Comments)
def comments_deleted_channels(sender, instance, **kwargs):
print('this post_save receiver is called, the instance post id', instance.cmt_post.id)
notes :
the instance with 'm2m_changed' it is a post object .
the instance with 'post_save and post_delete' it is a comment object
this is just an example , and change it based on your case/requirements.
i hope this helpful