I am getting the Value Error: Cannot query "post": Must be "UserProfile" instance when I make a get request to call PostListView.as_view().
Here is my model.py :
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.CharField(max_length=30)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField()
password = models.CharField(max_length=100)
def __str__(self):
return self.user.username
class Post(models.Model):
user = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
text = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
views.py :
class PostListView(ListAPIView):
serializer_class = PostSerializer
permission_classes = [AllowAny]
def get_queryset(self):
"""Returns only the object related to current user"""
user = self.request.user
return Post.objects.filter(user=user)
Also, I want a Foreign key relationship exists between User and Post on Model-level, not on the Database level.
user is UserProfile instance but request.user is a User instance
change this line like that to refernece to userprofile
user = self.request.user.userprofile
Related
I'm trying to implement a like system in Django, but I'm getting FOREIGN KEY constraint failed error
models.py
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="likes")
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="likes")
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user.username} {self.article.Title}"
class Meta:
ordering = ('-created_at',)
views.py
def like(request, slug, pk):
if request.user.is_authenticated:
try:
like = Like.objects.get(article__slug=slug, user_id=request.user.id)
like.delete()
except:
Like.objects.create(article_id=pk, user_id=request.user.id)
return redirect('blog:article_detail', slug)
urls.py
path('like/<slug:slug>/<int:pk>', views.like, name='like_article')
The below is my code about model Domain's Update:
serializer.py:
class DomainUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Domain
fields = "__all__"
models.py:
class Domain(models.Model):
domain_name = models.CharField(max_length=512, help_text='domain. eg.example.com')
cname = models.ForeignKey(
unique=True,
to=CNAMEModel,
on_delete=models.DO_NOTHING,
related_name="domains",
help_text="CNAME")
ssl_cert = models.TextField(max_length=40960, help_text="SSL cert + ca-bundle")
ssl_key = models.TextField(max_length=40960, help_text="SSL key")
ctime = models.DateTimeField(auto_now_add=True)
uptime = models.DateTimeField(auto_now=True)
def __str__(self):
return self.domain_name
def __unicode__(self):
return self.domain_name
class Meta:
verbose_name = "domain"
verbose_name_plural = "domain"
ordering = ['ctime']
class CNAMEModel(models.Model):
name = models.CharField(max_length=64, unique=True, help_text=". eg:gat.demo.com")
desc = models.CharField(max_length=5120, null=True, blank=True, help_text="desc")
desc_en = models.CharField(max_length=5120, null=True, blank=True")
user = models.OneToOneField(unique=True, to=AuthUser, on_delete=models.DO_NOTHING, help_text="belong user")
is_active = models.BooleanField(default=True)
ctime = models.DateTimeField(auto_now_add=True)
uptime = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
def __unicode__(self):
return self.name
class Meta:
verbose_name = "CNAME"
verbose_name_plural = "CNAME"
ordering = ['ctime']
views.py:
class DomainUpdateAPIView(UpdateAPIView):
serializer_class = DomainUpdateSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
queryset = Domain.objects.all()
You see Domain belong to CNAME, CNAME belong to a user.
I have a question, how can I make a permission for checking the Domain only can be update by the belonged users or AdminUser(IsAdminUser have solved)?
Or use other way rather than permission.
You can have a additional custom permission:
from rest_framework import permissions
from rest_framework.exceptions import PermissionDenied
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow creator of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the creator of the movie
return obj.cname.user == request.user
And in the views IsOwnerOrReadOnly can be included:
from .permissions import IsOwnerOrReadOnly
class DomainUpdateAPIView(UpdateAPIView):
serializer_class = DomainUpdateSerializer
permission_classes = [IsAuthenticated, IsAdminUser, IsOwnerOrReadOnly]
queryset = Domain.objects.all()
I have a model Offlinecheckout and CartItem model. I want to add a filter queryset of the cart field in the offline checkout model. As It is showing the cart of all users. I want to filter queryset by request.user.So that cart filed will show in the cart request.user only not other users.
How I can add a filter in that field.
Models.py
class OfflineCheckOut(models.Model):
user = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
cart = models.ManyToManyField('cart.CartItem')
time_slot = models.ForeignKey('category.TimeSlot', on_delete=models.CASCADE)
state = models.CharField(max_length=254)
city = models.CharField(max_length=254)
address = models.CharField(max_length=254)
landmark = models.CharField(max_length=254, blank=True)
# order_id = models.ForeignKey('cart.CartModel', on_delete=models.CASCADE)
date = models.DateField()
tsn_amount = models.IntegerField()
def __str__(self):
return self.user.username
class CartItem(models.Model):
cart = models.ForeignKey('CartModel', on_delete=models.CASCADE)
user = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
service = models.ForeignKey('accounts.SubCategory', on_delete=models.CASCADE)
defects = models.ForeignKey('category.Defects', on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
price = models.IntegerField()
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now_add=True)
serializers.py
from rest_framework import serializers
from .models import Address, Date, OfflineCheckOut
class OfflineSerializer(serializers.ModelSerializer):
class Meta:
model = OfflineCheckOut
fields = "__all__"
views.py
class offlineViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
def get_queryset(self):
user = self.request.user
if user.is_authenticated:
if user is not None:
if user.is_active and user.is_superuser or user.is_Customer:
return OfflineCheckOut.objects.all()
raise PermissionDenied()
raise PermissionDenied()
raise PermissionDenied()
serializer_class = OfflineSerializer
You can filter relations by using FilteredRelation in Django
Please change your views.py as follow
from django.db.models import FilteredRelation, Q
class offlineViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
def get_queryset(self):
user = self.request.user
if user.is_authenticated:
if user is not None:
if user.is_active and user.is_superuser or user.is_Customer:
### Use filtered relation
return OfflineCheckOut.objects.filter(user=user).annotate(user_cart=FilteredRelation('cart', condition=Q(cart__user=user)))
raise PermissionDenied()
raise PermissionDenied()
raise PermissionDenied()
serializer_class = OfflineSerializer
I hope this will help you to resolve an issue.
Please refer FilteredRelation objects for more information.
If you require further help please comment
I've a registration form, where user must chose one of 2 options.
Django renders all correctly, django admin also have it ok, but db records all possible choices as value.
forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email','password1','password2']
class UserProfileForm(forms.ModelForm):
terms_compliance = forms.BooleanField(label=mark_safe('I agree with terms and conditions '))
class Meta:
model = UserProfile
widgets = {'role': forms.RadioSelect}
fields = ('role','terms_compliance')
def __init__(self):
self.fields['terms_compliance'].initial = True
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
role_choices = [('publisher','Publisher'), ('advertiser','Advertiser')]
role = models.CharField(max_length=15, choices=role_choices, default=None)
terms_compliance = models.BooleanField()
def __str__(self):
return self.user.username
In new instance (which is user.userprofile.role_choices) I need advertiser or publisher, but all I have is: [('publisher','Publisher'), ('advertiser','Advertiser')]
If you want to provide choices in a Database Field. Do like this:
class UserProfile(models.Model):
class RoleChoice(ChoiceEnum):
PUBLISHER = 'Издатель'
ADVERTISER = 'Рекламодатель'
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(max_length=15, choices=RoleChoice.choices(), default=None)
terms_compliance = models.BooleanField()
def __str__(self):
return self.user
In Views.py, populate the DB like this.
For example:
...
choice = request.query_params.get('choice') or UserProfile.RoleChoice.PUBLISHER.value
...
For more details read from here: https://django-mysql.readthedocs.io/en/latest/model_fields/enum_field.html
I want relate my Profile model with User model from class AbstractUserModel with OnetoOneFields. Is it possible? Or any solution with this problem. Here my models.py
from django.db import models
#from django.contrib.auth.models import User
from django.contrib.auth.models import (
AbstractBaseUser
)
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
class Profile(models.Model):
#HERE
user = models.OneToOneField(AbstractBaseUser, on_delete=models.CASCADE)
nama_lengkap = models.CharField(max_length=100, blank=True, null=True)
tgl_lahir = models.DateField(null=True, blank=True)
alamat = models.CharField(max_length=255)
foto_profil = models.ImageField(upload_to='foto_profil',blank=True)
jabatan = models.ForeignKey(Jabatan, on_delete=models.CASCADE)
def __str__(self):
return "{} - {}".format(self.user, self.nama_lengkap)
when I migrate this, just show some errors message like this:
SystemCheckError: System check identified some issues:
ERRORS:
users.Profile.user: (fields.E300) Field defines a relation with model 'AbstractBaseUser', which is either not installed, or is abstract.
users.Profile.user: (fields.E307) The field users.Profile.user was declared with a lazy reference to 'auth.abstractbaseuser', but app 'auth' doesn't provide model 'abstractbaseuser'.
thanks in advance
you need to replace this
user = models.OneToOneField(AbstractBaseUser, on_delete=models.CASCADE)
with
user = models.OneToOneField(User, on_delete=models.CASCADE)
However I recommend you doing it different way:
Instead of creating second User model, extend existing one:
#models.py
class ProfileUser(AbstractUser):
extra_field = models.CharField(max_length=100)
username = models.CharField(max_length=20) # modifing existing field
```
```
#settings.py
AUTH_USER_MODEL = "app_name.ProfileUser"