How to fetch self and friends posts on django model - django

Profile.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png', upload_to='profile_pics')
slug = AutoSlugField(populate_from='user')
bio = models.TextField(blank=True)
friends = models.ManyToManyField("Profile", blank=True)
def __str__(self):
return str(self.user.username)
def get_absolute_url(self):
return "/users/{}".format(self.slug)
class PostListView(ListView):
model = PostForNewsFeed
template_name = 'feed/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 10
count_hit = True
slug_field = 'slug'
def get_context_data(self, **kwargs):
context = super(PostListView, self).get_context_data(**kwargs)
context.update({
'popular_posts': PostForNewsFeed.objects.order_by('-hit_count_generic__hits')[:3],
})
if self.request.user.is_authenticated:
liked = [i for i in PostForNewsFeed.objects.all() if Like.objects.filter(user = self.request.user, post=i)]
context['liked_post'] = liked
return context
class PostForNewsFeed(models.Model):
title = models.CharField(max_length=100, blank=True)
description = models.CharField(max_length=255, blank=True)
slug = models.SlugField(unique=True, max_length=100, blank=True)
pic = models.ImageField(upload_to='path/to/img', default=None,blank=True)
youtubeVideo = models.CharField(max_length=200, null=True, blank=True)
date_posted = models.DateTimeField(default=timezone.now)
user_name = models.ForeignKey(User, on_delete=models.CASCADE)
tags = models.CharField(max_length=100, blank=True)
hit_count_generic = GenericRelation(HitCount, object_id_field='object_pk',
related_query_name='hit_count_generic_relation2', default=1)
How to fetch Posts from self and friends posts via orm query?
path('', PostListView.as_view(), name='home2'),

You can filter the queryset with:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
class PostListView(LoginRequiredMixin, ListView):
model = PostForNewsFeed
template_name = 'feed/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 10
count_hit = True
slug_field = 'slug'
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(
Q(user_name=self.request.user) |
Q(user_name__profile__friends__user=self.request.user)
).distinct()
# …
We thus retrieve PostForNewsFeeds such that the user of the user_name is the logged in user (self.request.user), or if the user_name has the logged in user in the friends relation.
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixin mixin [Django-doc].

Related

How to Get All Posts with post_status django rest api?

In my project, How can I get all posts with post_status like- publish, pending, draft, spam.
I want to query with post_status.
Post Model
`
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.CharField(max_length=255, unique= True, editable=False)
author = models.ForeignKey(User, on_delete=models.CASCADE)
subtitle = models.CharField(max_length=255, null=True, blank=True)
description = models.TextField(max_length=5555, null=True, blank=True)
image = models.ImageField(blank=True, upload_to=post_image_path)
image_caption = models.CharField(max_length=255, blank=True)
post_status = models.CharField(max_length=255)
comment_status = models.CharField(max_length=255)
post_type = models.CharField(max_length=50)
comment_count = models.IntegerField(null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True)
tags = models.ManyToManyField(Tag, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
updatedAt = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def __str__(self):
return self.title
`
Serializer.py
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
read_only_fields = ['author']
How to implement in view?
The below snippet should work for your query.
class PostListView(generics.ListAPIView):
serializer_class = PostSerializer
def get_queryset(self):
queryset = Post.objects.all()
post_status = self.request.query_params.get('post_status')
if username is not None:
queryset = queryset.filter(post_status=post_status)
return queryset
Snipped adapted from Django Rest Framework - Filtering
views.py
from django.db.models import Q
from .serializers import PostSerializer
from rest_framework.generics import ListAPIView
from .models import Post
class PostListAPIView(ListAPIView):
serializer_class = PostSerializer
def get_queryset(self):
queryset = Post.objects.filter(Q(post_status__contains='publish') | Q(post_status__contains='pending') | Q(post_status__contains='draft') | Q(post_status__contains='spam'))
return queryset
``

NOT NULL constraint failed: products_order.user_id when trying to save serializer django rest frame work

django rest framework gives me this error when i am trying to perform a post request to create a new order even though i specified the usr value in my serializer.save method.
here is my view
class OrderListCreateAPI(generics.ListCreateAPIView):
serializer_class = OrderSerializer
permission_classes = [IsOwner]
def get_queryset(self):
user = self.request.user
return Order.objects.filter(user= user)
def perform_update(self, serializer):
instance = serializer.save(user = self.request.user)
order = Order.objects.get(id = instance['id'].value)
order.item.quantity -= order.quantity
order.save()
my models.py
payment_methods = ((1,'credit card'),(2, 'cash'),(3, 'paypal'))
class Product(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
image = models.ImageField(upload_to = 'images/', height_field=300, width_field=300)
price = models.IntegerField()
quantity = models.IntegerField()
seller = models.ForeignKey(User, on_delete=models.CASCADE, related_name='products')
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Order(models.Model):
item = models.ForeignKey(Product, on_delete= models.CASCADE, related_name='orders')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='orders')
quantity = models.IntegerField()
payment_options = models.CharField(choices=payment_methods, max_length=50)
Delivery = models.CharField(max_length=200)
my serializers
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['id', 'title', 'description','image', 'price', 'quantity', 'seller', 'date']
read_only_fields = ['date', 'seller']
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
read_only_fields = ['user']
You need to use perform_create and not perform_update in your view.
class OrderListCreateAPI(generics.ListCreateAPIView):
serializer_class = OrderSerializer
permission_classes = [IsOwner]
def get_queryset(self):
user = self.request.user
return Order.objects.filter(user= user)
def perform_create(self, serializer):
instance = serializer.save(user = self.request.user)
order = Order.objects.get(id = instance['id'].value)
order.item.quantity -= order.quantity
order.save()

Django rest framework API with filter

Models.py
Categories:
class Category_product(models.Model):
category_name = models.CharField(max_length=200, unique=True)
def __str__(self):
return self.category_name
Products:
class Warehouse(models.Model):
category_product = models.ForeignKey(
Category_product, on_delete=models.CASCADE)
product_name = models.CharField(max_length=200, unique=True)
condition = models.BooleanField(default=False)
amount = models.IntegerField()
barcode = models.BigIntegerField()
f_price = models.CharField(max_length=255, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.product_name
urls.py
path('products-list/', views.WarehouseList.as_view()),
Views.py
class WarehouseList(generics.ListCreateAPIView):
queryset = Warehouse.objects.all()
serializer_class = WarehouseSerializer
Serializers.py
# SERIALIZER OF CATEGORY PRODUCTS
class Category_productSerializer(serializers.ModelSerializer):
class Meta:
model = Category_product
fields = ['id', 'category_name']
# SERIALIZER OF WAREHOUSE
class WarehouseSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField(
source='category_product.category_name')
def get_serializer(self, *args, **kwargs):
if isinstance(kwargs.get('data', {}), list):
kwargs['many'] = True
return super(Category_productSerializer, self).get_serializer(*args, **kwargs)
class Meta:
model = Warehouse
fields = ['id', 'category_product', 'category_name', 'condition',
'product_name', 'amount', 'barcode', 'f_price', 'created_at', 'updated_at']
I want to get products by exact category
For example:
I have product category
{
"id": 1
"category_name": "Electronics"
}
If I send GET request to api/products-list/?cat=1
I want to get products which have this category
Create a get_queryset method as follow.
class WarehouseList(generics.ListCreateAPIView):
queryset = WareHouse.objects.all()
serializer_class = WarehouseSerializer
def get_queryset(self):
cat = self.request.query_params.get('cat', None)
if cat is not None:
self.queryset = self.queryset.filter(category_product__id=cat)
return self.queryset

Django CreateView filter foreign key in select field

I need some help with Django 2 and Python 3.
I'm using a CreateView to add new reccords in my database, but I need to make a filter for my Aviso form page to make the select field (field turma) to show only instances where the representante is the current user.
This is my model:
class Turma(models.Model):
nome = models.CharField(max_length=120, blank=False, null=False, help_text='Obrigatório.')
alunos = models.ManyToManyField(User, help_text='Obrigatório', related_name='alunos_matriculados')
data_cadastro = models.DateField(auto_now_add=True)
representante = models.ForeignKey(User, on_delete=models.PROTECT, blank=False, null=False)
colegio = models.ForeignKey(Colegio, on_delete=models.PROTECT, blank=False, null=False, help_text='Obrigatório.')
class Aviso(models.Model):
data_final = models.DateField(auto_now=False, auto_now_add=False, blank=False, null=False, verbose_name="Data Final")
comentarios = models.TextField(null=True, blank=True)
ultima_modificacao = models.DateField(auto_now=True)
data_post = models.DateField(auto_now_add=True)
turma = models.ForeignKey(Turma, on_delete=models.PROTECT, null=False, blank=False)
materia = models.ForeignKey(Materia, on_delete=models.PROTECT, null=False, blank=False)
This is my view:
class AvisoCreateView(LoginRequiredMixin, CreateView): #Cadastro de Aviso
template_name = 'form.html'
model = models.Aviso
login_url = '/login/'
success_url = reverse_lazy('visualizar_aviso')
fields = [
'turma',
'materia',
'tipo_aviso',
'comentarios',
'data_final'
]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['titulo'] = 'Cadastrar aviso'
context['input'] = 'Adicionar'
return context
How could that be done?
You can add a queryset to the ForeignKey field.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'].fields['turma'].queryset = Turma.objects.filter(representante=self.request.user)
context['titulo'] = 'Cadastrar aviso'
context['input'] = 'Adicionar'
return context
You could create a ModelForm for that model.
And based on this answer you could override the forms __init__() method to alter the fields queryset.
class AvisoForm(forms.ModelForm):
class Meta:
model = Aviso
fields = [
'data_final', 'comentarios', 'ultima_modificacao', 'data_post',
'turma', 'materia',
]
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# restrict the queryset of 'Turma'
self.fields['turma'].queryset = self.fields['turma'].queryset.filter(
representante=user)
Then, in your view, replace the attribute fields with form_class:
class AvisoCreateView(LoginRequiredMixin, CreateView):
...
form_class = AvisoForm
...
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
Maybe you need to adjust a few things for your specific case.
Let us know if that solved it.

django url issue using mutiple regular expressions

I am having an issue with an url and regular expression I get the error
AttributeError: Generic detail view EmployeeDetailView must be called with either an object pk or a slug.
What I am to achieve is to get to a user detail page coming from a specific project
url(r'^project/(?P<pk>[0-9]+)/$',views.ProjectDetailView.as_view(), name='ProjectDetails'),
url(r'^project/(?P<pk1>[0-9]+)/(?P<pk2>[0-9]+)/$',views.EmployeeDetailView.as_view(), name='EmployeDetails'),
my view is :
Project detail :
class ProjectDetailView(generic.DetailView, LoginRequiredMixin):
#import pdb; pdb.set_trace()
model = Project
template_name = 'project_details.html'
def get_context_data(self, **kwargs):
context = super(ProjectDetailView, self).get_context_data(**kwargs)
try:
team_name = Project.objects.get(id=self.kwargs['pk']).team_id.members.all()
context['team_name'] = team_name
except AttributeError:
pass
return context
class EmployeeDetailView(generic.DetailView, LoginRequiredMixin):
#import pdb; pdb.set_trace()
model = MyUser
template_name = 'Employee_Details.html'
def get_context_data(self, **kwargs):
context = super(EmployeeDetailView, self).get_context_data(**kwargs)
employee_name = MyUser.objects.get(id=self.kwargs['pk'])
context['employee_name'] = employee_name
return context
HTML link :
<span class="fa fa-id-card-o" aria-hidden="true"> Show Results
models:
MyUser models:
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
first_name = models.CharField(max_length=150, blank=True, null=True)
last_name = models.CharField(max_length=150, blank=True, null=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_hr = models.BooleanField(default=False)
is_candidate = models.BooleanField(default=False)
is_employee = models.BooleanField(default=False)
company = models.CharField(max_length=100, blank=True, null=True)
Project model:
class Project(models.Model):
name = models.CharField(max_length=250)
team_id = models.ForeignKey(Team, blank=True, null=True)
project_hr_admin = models.ForeignKey('registration.MyUser', blank=True, null=True)
candidat_answers = models.ManyToManyField('survey.response')
Team models:
class Team(models.Model):
team_name = models.CharField(max_length=100, default = '')
team_hr_admin = models.ForeignKey(MyUser, blank=True, null=True)
members = models.ManyToManyField(MyUser, related_name="members")
could you please help me to figure it ? thx you ;)
Django doesn't know how to use pk1 and pk2 to fetch the object for the view. I would override the get_object method and fetch the object there.
from django.shortcuts import get_object_or_404
# Note mixin should come first
class EmployeeDetailView(LoginRequiredMixin, generic.DetailView):
model = MyUser
template_name = 'Employee_Details.html'
def get_object(self, queryset=None):
return get_object_or_404(MyUser, pk=self.kwargs['pk2'], project=self.kwargs['pk1'])
...
Another option is to set pk_url_kwarg = 'pk2'. This tells Django that pk2 is the primary key of the MyUser object, so there is no need to override get_object. However if you do this, then Django will ignore the pk1 from the URL.
class EmployeeDetailView(generic.DetailView, LoginRequiredMixin):
#import pdb; pdb.set_trace()
model = MyUser
pk_url_kwarg = 'pk2'
template_name = 'Employee_Details.html'