Blog on Django, querysets for fetch logged in user's posts - python

I'm building a blog on Django and know i have to make a personal page for see all the posts published by the user we're logged in now.
I'm using some querysets so.
Her my code
my models.py
from django.db import models
from django.conf import settings
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
Here my forms.py
from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
from .models import Post
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username','email','password1','password2','user_permissions','is_staff','date_joined']
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'text', 'author']
And that's the view which is gonna filter the posts in base of the logged user
from django.contrib.auth.models import User
from django.contrib import messages
from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from .forms import CreateUserForm
from .models import Post
from .forms import PostForm
def user_data(request, pk):
user_data = User.objects.get(pk=pk)
posts = user_data.post_set.filter(author=user_data)
context = {'user_data':user_data, 'posts':posts}
return render(request, 'account/user_data.html', context)
#So it returns me just the user data like name, email or date_joined but not his posts

This should give you posts of logged in users from your view
def user_data(request, pk):
posts=Post.objects.filter(author=request.user)
context = {'posts':posts}
return render(request, 'account/user_data.html', context)

Related

NOT NULL constraint when creating a new user in django

I created a Django API to create a new user. However, when I try to create a user I get the error message:
IntegrityError at /api/v1/users/register/ NOT NULL constraint failed: accounts_user.user_id
This is what I have in models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class User(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100, blank=True)
location = models.CharField(max_length=100, blank=True)
password = models.CharField(max_length=32)
email = models.EmailField(max_length=150)
signup_confirmation = models.BooleanField(default=False)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def update_profile_signal(sender, instance, created, **kwargs):
if created:
User.objects.create(user=instance)
instance.profile.save()
In serializers.py
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('user_id', 'name', 'location', 'password', 'email', 'signup_confirmation')
and my views.py
from rest_framework import viewsets
from .serializers import UserSerializer
from .models import User
from rest_framework.decorators import action
from .forms import SignUpForm
from .tokens import account_activation_token
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all().order_by('name')
serializer_class = UserSerializer
#action (detail=True, methods=['post'])
def register(self, request):
print(request)
Any ideas on what I can do to resolve this error
As John wrote in a comment:
Here you have a problem: fields = ('user_id',...).
I also advise you to change your User model. If you don't need separating (I suppose you don't), it is way better to create your User with inheritance directly from AbstractUser instead of creating in fact doubled User models.
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
...
In this way you will already have username, password and email, but you can add anything else in same model, instead of using user.user etc.

different queryset based on permissions in Django Rest Framework

I have seen this link, but I didn't find anything related to my question helping it being resolved.
Imagine we have to create a blog, in which posts have two status:
is_draft
published (published == !is_draft)
So, each user should see all of his/her posts, whether it is draft or not. In addition, Other users should see the published posts of rest of the users.
I am using viewsets in django and I know that we should have different queryset based on the current user permissions but I don't know how.
models.py:
from django.db import models
# Create your models here.
from apps.authors.models import Author
class Post(models.Model):
author = models.ForeignKey(
Author,
related_name="posts",
on_delete=models.CASCADE,
)
title = models.TextField(
null=True,
blank=True,
)
content = models.TextField(
null=True,
blank=True,
)
is_draft = models.BooleanField(
default=True
)
views.py:
from django.shortcuts import render
from rest_framework import viewsets, permissions
# Create your views here.
from apps.posts.models import Post
from apps.posts.serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
def get_permissions(self):
if self.action == "create":
self.permission_classes = [permissions.IsAuthenticated]
elif self.action == "list":
pass #I don't know how can I change this part
return super(PostViewSet, self).get_permissions()
serializers.py:
from rest_framework import serializers
from apps.posts.models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
Change your queryset like this in your viewset. That way, only your desired posts will be accessed/permitted by the view:
from django.shortcuts import render
from django.db.models import Q
from rest_framework import viewsets, permissions
# Create your views here.
from apps.posts.models import Post
from apps.posts.serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
serializer_class = PostSerializer
def get_permissions(self):
if self.action == "create":
self.permission_classes = [permissions.IsAuthenticated]
return super(PostViewSet, self).get_permissions()
def get_queryset(self, *args, **kwargs):
current_user = self.request.user
current_author = Author.objects.get(user=current_user) #assuming your author class has foreign key to user
return Post.objects.filter(Q(author=current_author) | Q(is_draft=False))

Can I link my customer model to my user model?

I'm working an a django e-commerce website where a user has to be a customer. But when I create a new user, it assigns it to the the superuser not the new user and get this error:
Exception Value: User has no customer.
But i can also go to my admin panel and re-assign the customer to the user.
django admin panel
How can I fix this please?
My customer model
class Customer(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=255, null=True)
email = models.CharField(max_length=255, null=True)
def __str__(self):
return self.name
members/views.py to create new user and customer
from django.shortcuts import render
from django.views import generic
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from shop.models import Customer
from django.views.generic import CreateView
from .forms import CreateCustomerForm
# Create your views here.
class UserRegisterView(generic.CreateView):
form_class = UserCreationForm
template_name = 'registration/signup.html'
success_url = reverse_lazy('customer')
class CreateCustomerView(CreateView):
form_class = CreateCustomerForm
template_name = 'registration/customerProfile.html'
success_url = reverse_lazy('login')
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
My shop view
def shop(request):
data = cartData(request)
cartItems = data['cartItems']
products = Product.objects.all()
context = {'products': products, 'cartItems': cartItems}
return render(request, 'shop/shop.html', context)
The Customer model has a one-to-one unique relationship with User models.
Use contrib.auth.models.User
Example:
class Customer(models.Model):
user = models.ForeignKey(User, unique=True, related_name='customer')
Other the other hand (Slightly out of the context of the question), you can edit the User model to add the customer
from django.contrib.auth.models import User, UserManager
class CustomUser(User):
# Add the column you want o add.
# Use UserManager to get the create_user method, etc.
objects = UserManager()

Django Rest Framework - Displaying the User's Profile

My users/models.py file looks as below.
class User(AbstractUser):
is_customer = models.BooleanField(default=False)
is_courier = models.BooleanField(default=False)
is_merchant = models.BooleanField(default=False)
class Profile(models.Model):
contact_number = models.CharField(max_length=10, unique=True)
rating = models.IntegerField(blank=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
My current users/serializers.py looks like below.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
My users/api.py looks like below.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = UserSerializer
My users/urls.py has the below:
router.register('api/users', UserViewSet, 'users')
My current setup works well with the UserViewSet. http://127.0.0.1:8000/api/users/ displays all the users and http://127.0.0.1:8000/api/users/1/ displays the user according to the ID.
My question is, How can I load up the user profile when I goto the below the URL http://127.0.0.1:8000/api/users/1/profile
Any help is much appreciated. Thank you in advance.
Create a new serializer for Profile model
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = "__all__"
then create a new view class for the Profile.
from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
class ProfileAPI(APIView):
def get(self, request, *args, **kwargs):
user = get_object_or_404(User, pk=kwargs['user_id'])
profile_serializer = ProfileSerializer(user.profile)
return Response(profile_serializer.data)
Then, wire up the view in urls.py
urlpatterns = [
# your other url configs
path('api/users/<user_id>/profile/', ProfileAPI.as_view())
]
Update-1
Implementation using ViewSet class
from rest_framework import viewsets
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
class ProfileAPI(viewsets.ViewSet):
def get(self, request, *args, **kwargs):
user = get_object_or_404(User, pk=kwargs['user_id'])
profile_serializer = ProfileSerializer(user.profile)
return Response(profile_serializer.data)
Update-2
from rest_framework import viewsets
class ProfileAPI(viewsets.ModelViewSet):
serializer_class = ProfileSerializer
def get_queryset(self):
return Profile.objects.filter(user=self.kwargs['user_id'])
and in your urls.py register the viewset as
router.register('api/users/(?P<user_id>\d+)/profile', ProfileAPI, base_name='profile_api')
i have used **AbstractUser ** and **custom user manager **
i have used ViewSets.ViewSet along with Model Serializers
#urls.py file#
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProfileViewSet, LoginViewSet, RegisterViewSet
router = DefaultRouter()
router.register(r'register', RegisterViewSet, basename='register')
router.register(r'login', LoginViewSet, basename='login')
router.register(r'profile', ProfileViewSet, basename='profile')
urlpatterns = [
path('', include(router.urls)),
]
#views.py file#
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from .models import user_reg
from .serializers import RegisterSerializer
class ProfileViewSet(ViewSet):
def partial_update(self, request, pk=None): #partially update the profile
try:
user_detail = user_reg.objects.get(pk=pk)
serializer = RegisterSerializer(user_detail,data=request.data, partial=True)
if not serializer.is_valid():
return Response({'data':'internal server error','message':'error aa gyi'},500)
serializer.save()
except Exception as e:
return Response('some exception occured' + str(e))
return Response('record Updated successfully')
def retrieve(self,request, pk=None): #get or retrieve the profile from database
queryset = user_reg.objects.get(pk=pk)
serializer_class = RegisterSerializer(queryset)
return Response(serializer_class.data)
#serializer.py file#
from rest_framework import serializers
from .models import user_reg
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = user_reg
fields = ('username','first_name','last_name','email') #custom fields i made
u can change this
#models.py#
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import UserManager
class user_reg(AbstractUser):
mobile = models.CharField(max_length=10, blank=True, null=True)
age = models.IntegerField(null=True,blank=False)
gender = models.CharField(max_length= 8,blank=True)
objects = UserManager()
class Meta:
verbose_name='user'

how to fill an author field with current username

I have looked at a lot of different places but none of their solutions work. This is most likely to do them being for older versions of django or my own stupidity. So I am making a blog type of app that for some reason is called reviews instead of blog... anyway I need to automatically fill up an author field with the username of the logged in user. Here is my models.py:
from django.db import models
from django.contrib.auth.models import User
#vars
# Create your models here.
class reviews(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.PROTECT,)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True, blank=True)
and forms.py:
from django import forms
from django.forms import ModelForm
from .models import reviews
from django.contrib.auth.decorators import login_required
class CreatePost_form(ModelForm):
class Meta:
model = reviews
exclude = ['author']
fields = ['title', 'body',]
and views:
from django.shortcuts import render, render_to_response
from .forms import CreatePost_form
from django.http import HttpResponseRedirect
# Create your views here.
def reviewlist(request):
return render
def index(request, ):
return render(request, template_name="index.html")
def CreatePost(request):
form = CreatePost_form(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/reviews/succesfulpost')
return render(request, "reviews/CreatePostTemplate.html", {'form':form})
def succesfulpost(request):
return render(request, "reviews/succesfulpost.html")
def CreatePost(request):
form = CreatePost_form(request.POST)
if form.is_valid():
form.save(commit=False)
form.author = request.user
form.save()
return HttpResponseRedirect('/reviews/succesfulpost')
As simple as that. Rather than actually saving and committing the data, you simply save without committing then you're able to change the value of the excluded field.

Categories