How to join two different modal in django? - python

I'm using django 3.2. And DB name postgres.
I'm stuck in a problem where i want to combine two modals.
I have following two modals
1- Profiles
2- Ratings foreignKey(Profiles)
now I want to return profiles list with their ratings.
And this is what i'm unable to achieve. Actually I don't know how to do that. I think it can be done by inner join by profile_id but how to do this with django ?
profiles/views.py:
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def profile_list(request):
if request.method=="GET":
kind = kind.lower()
paginator = CustomPagination()
paginator.page_size = 10
print("dat da da da da ==>> ",request.data)
coordinates = request.data["coordinates"]
nearby_count = Profile.objects.nearby_count(coordinates)
total_count = nearby_count
total_page = total_page_counter(nearby_count)
profiles_queryset = Profile.objects.nearby_ground_list(coordinates)
## Rating.objects ????
page_data_of_profiles=None
try:
page_data_of_profiles = paginator.paginate_queryset(profiles_queryset, request)
except:
pass
serializer = ProfileSerializer(page_data_of_profiles, many=True)
return Response({"status":"success","message": "Ok","total_count":total_count,"total_page":total_page, "data": serializer.data},status=status.HTTP_200_OK)
ratings/modals.py
class Rating(models.Model):
user = models.ForeignKey(User, verbose_name=_("user"), on_delete=models.CASCADE,null=True,blank=True)
profile = models.ForeignKey(Profile, verbose_name=_("profile"), on_delete=models.CASCADE)
stars = models.IntegerField(_("stars"),default=0)
is_remove = models.BooleanField(_("is_remove"),default=False)
create_time = models.DateTimeField(_("Create time"), default=timezone.now)
profiles/modals.py
# Create your models here.
class Profile(models.Model):
owner = models.ForeignKey(User, verbose_name=_("Owner"), on_delete=models.CASCADE)
name = models.CharField(_("Name"), max_length=150,null=True)
location = geo_models.PointField(geography=True, default=Point(0.0, 0.0),null=True,blank=True)
is_premium = models.BooleanField(_("premium"), default=False)
is_remove = models.BooleanField(_("Remove"), default=False)
create_time = models.DateTimeField(_("Create time"), default=timezone.now)

users_with_ratings = Rating.objects.all().values("user__name", "stars").distinct("user")

Related

Django Query is not ordering / Sorting Correctly in pagination model in rest framework

I have 705 Meta#Data of Instagram videos but I am unable to sort it by name | id | uploading date or any order query.
My MetaData model is
class MetaData(models.Model):
# Info
id = models.IntegerField(primary_key=True)
tag = models.CharField(max_length=500)
# User Info
username = models.CharField(max_length=400)
followers = models.IntegerField()
verified = models.BooleanField()
profile = models.URLField()
# Video Info
upload_date = models.DateField()
upload_time = models.TimeField()
views = models.IntegerField()
duration = models.CharField(max_length=50)
comments = models.IntegerField()
likes = models.IntegerField()
dimension = models.CharField(max_length=50)
framerate = models.CharField(
max_length=100, blank=True, default='Not Found')
# Post
link = models.URLField()
codecs = models.CharField(max_length=200, blank=True, default='Not Found')
caption = models.CharField(max_length=100, blank=True, default='Not Set')
status = models.CharField(max_length=20, choices=(
('Pending', 'Pending'), ('Acquired', 'Acquired'), ('Rejected', 'Rejected')), default='Pending')
I am using Django rest framework pagination and getting my filters fields in parameters
def fetchVideosContentwithFilter(request, filters, directory=None):
paginator = PageNumberPagination()
paginator.page_size = 12
# Parameters
flts = ['upload_date']
if filters:
flts = json.loads(filters)
if 'upload_date' in flts:
flts.append('upload_time')
if directory and directory != 'all':
objs = MetaData.objects.filter(tag=directory)
else:
objs = MetaData.objects.all()
pages = paginator.paginate_queryset(objs.order_by(*flts), request)
query = s.MetaDataSerializer(pages, many=True)
return paginator.get_paginated_response(query.data)
I also try or replace
*paginator.paginate_queryset(objs.order_by(flts), request) with
paginator.paginate_queryset(objs.order_by('-id'), request)
but in vain data is not ordering correctly
Maybe, you can solve your task with DRF's ListAPIView.
from rest_framework.filters import OrderingFilter
from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPagination
# Your custom pagination
class DefaultPagePagination(PageNumberPagination):
max_page_size = 100
page_size_query_param = "page_size"
page_size = 12
# Your view
class FetchVideosContentwithFilter(ListAPIView):
serializer_class = MetaDataSerializer
pagination_class = DefaultPagePagination
filter_backends = [
OrderingFilter,
]
ordering_fields = ["title", "created_at", "updated_at"]
def get_queryset(self):
# I'm not sure, how you get the directory param.
# I assume, you take it from query_params
directory = self.request.query_params.get('directory')
if directory and directory != 'all':
objs = MetaData.objects.filter(tag=directory)
else:
objs = MetaData.objects.all()
return objs
ListAPIView uses ListModelMixin, that implements pagination logic
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

Django - expected type pk, received str [Many to many]

I have a webapp where we can create communities with django as a backend, but when i try to send a POST to create a community, I get:
community_configuration: ["Incorrect type. Expected pk value, received str."]
My POST:
{
title: knkn kn .k jbjnmn,
logo: [object File],
is_active: true,
description: test,
welcome_message: Welcome message,
org_id: 114,
community_configuration: About us,Community news,FAQs,Supporters,Resources,
}
Here are my serializers:
class MicroConfigurationSerializer(serializers.ModelSerializer):
class Meta:
model = MicroConfiguration
fields = [
'name',
]
def to_representation(self, instance):
return instance.name
class CommunityConfigurationSerializer(serializers.ModelSerializer):
micro_configurations = MicroConfigurationSerializer(many=True, read_only=True)
class Meta:
model = CommunityConfiguration
fields = '__all__'
class CommunitySerializer(serializers.ModelSerializer):
logo = serializers.SerializerMethodField()
organisation = serializers.SerializerMethodField()
community_configuration = CommunityConfigurationSerializer()
class Meta:
model = Community
fields = (
...
etcetc
...
)
Heres my model:
class MicroConfiguration(core_models.BaseModel):
name = models.CharField(max_length=32, unique=True)
permissions = models.ManyToManyField(Permission)
def __str__(self):
return self.name
class CommunityConfiguration(core_models.BaseModel):
name = models.CharField(max_length=32)
micro_configurations = models.ManyToManyField(MicroConfiguration)
permission_group = models.ForeignKey(
Group,
on_delete=models.SET_NULL,
null=True
)
def __str__(self):
return self.name
class Community(core_models.BaseModel):
accounts = models.ManyToManyField(
settings.AUTH_USER_MODEL,
through='associates.AccountCommunity',
through_fields=('community', 'account')
)
goals = models.ManyToManyField(Goal, through='associates.CommunityGoal')
type = models.ManyToManyField(CommunityType, through='CommunityAttribute')
communities = models.ManyToManyField(
'self',
through='associates.CommunityCommunity',
symmetrical=False,
)
crossposts = models.ManyToManyField(
Action,
through='activities.CommunityCrosspost',
through_fields=('community', 'action'),
related_name='communities',
)
title = models.CharField(max_length=64)
logo = models.ImageField(null=True, blank=True)
intro_media = models.ForeignKey(
'associates.MediaStore',
null=True,
on_delete=models.SET_NULL
)
website_url = models.CharField(max_length=256, blank=True)
is_invite_only = models.BooleanField(default=False)
description = models.TextField(blank=True)
intro_message = models.TextField(blank=True)
welcome_message = models.TextField(blank=True)
signup_autojoin = models.BooleanField(default=False)
community_configuration = models.ForeignKey(
CommunityConfiguration,
default=1,
null=True,
on_delete=models.SET_NULL,
help_text='Do not edit directly, create a new custom config instead, \
as it is reference by difference community.',
)
objects = models.Manager()
associates = AssociationManager()
#property
def url(self):
return reverse(
'communities:detail',
kwargs={
'id': self.id,
}
)
class Meta:
verbose_name = 'Community'
verbose_name_plural = 'Communities'
def __str__(self):
return self.title
Here's my views:
class CommunityCreateAPIView(CreateAPIView):
serializer_class = CommunityCreateSerializer
def create(self, request, **kwargs):
organisation_id = request.data.get('org_id')
micro_configurations_qd = request.data.copy()
micro_configurations = micro_configurations_qd.pop('community_configuration', False)
if micro_configurations:
micro_configurations = micro_configurations[0].split(',')
user = request.user
data = {}
permitted = AccountOrganisation.objects.filter(
account=user,
organisation_id=organisation_id,
is_active=True,
association__permissions__codename='add_community',
).exists()
if not permitted and not request.user.is_superuser:
data['message'] = 'Action not allowed'
return Response(
data=data,
status=status.HTTP_400_BAD_REQUEST,
)
response = super().create(request, **kwargs)
if response.status_code == 400:
data['message'] = 'Failed to update community'
return Response(
data=data,
status=status.HTTP_400_BAD_REQUEST,
)
community_id = response.data.get('id')
OrganisationCommunity.objects.create(
community_id=community_id,
organisation_id=organisation_id,
)
association = Group.objects.get(name='Community Admin')
AccountCommunity.objects.create(
community_id=community_id,
account=user,
association=association,
)
if micro_configurations:
com_config_qs = CommunityConfiguration.objects.filter(
micro_configurations__name__in=micro_configurations
).annotate(
num_micro_config=Count('micro_configurations__name')
).filter(
num_micro_config=len(micro_configurations)
)
community_configuration = None
if micro_configurations:
for com_config in com_config_qs:
micro_config_count = com_config.micro_configurations.count()
if micro_config_count == len(micro_configurations):
community_configuration = com_config
break
if community_configuration:
Community.objects.filter(
pk=community_id
).update(
community_configuration=community_configuration
)
elif micro_configurations:
micro_qs = MicroConfiguration.objects.filter(
name__in=micro_configurations
)
community_config = CommunityConfiguration.objects.create(
name='Custom'
)
community_config.micro_configurations.set(micro_qs)
community_config.save()
Community.objects.filter(
pk=community_id
).update(
community_configuration=community_config
)
return response
I've been stuck with this for hours, any help?
Your serializer expects a pk (or id) of the community_configuration instance.
basically you have it set up so that you need to create a community_configuration entry first, then fetch the id of the new created entry and use that id when creating your community.
If you want to have the community_configuration instance to be created while creating the community then an option to do that would be to override the create method in the serializer and extract the community_configuration data then create a new entry for that model and use it, something like this
class CommunitySerializer(serializers.ModelSerializer):
# .. put your serializer code here
def create(self, validated_data):
community_configuration= validated_data.pop('community_configuration')
config_instance, created = CommunityConfiguration.objects.get_or_create(<community_configuration>) # modify this however you need to create the CommunityConfiguration instance
community_instance = community.objects.create(**validated_data, community_configuration=config_instance)
return community_instance
you will need to probably modify the code for it to follow your needs.
I didn't read all of your models, not sure how you are gonna create the nested models from the input value but you get the point.

Efficient Count of Related Models in Django

In my Django app, when I add the host_count field to my serializer to get the number of hosts for each domain, the performance of the API response suffers dramatically.
Without host_count: 300ms
With host_count: 15s
I tried adding 'host_set' to the prefetch_related method but it did not help.
Would an annotation using Count help me here? How can I optimize the fetching of this value?
serializers.py
class DomainSerializer(serializers.Serializer):
name = serializers.CharField(read_only=True)
org_name = serializers.CharField(source='org.name', read_only=True)
created = serializers.DateTimeField(read_only=True)
last_host_search = serializers.DateTimeField(read_only=True)
host_count = serializers.SerializerMethodField()
def get_host_count(self, obj):
return Host.objects.filter(domain=obj).count()
views.py
class DomainList(generics.ListAPIView):
def get(self, request, format=None):
domains = Domain.objects.prefetch_related('org').all()
serializer = DomainSerializer(domains, many=True)
return Response(serializer.data)
models.py
class Domain(models.Model):
created = models.DateTimeField(auto_now_add=True)
last_host_search = models.DateTimeField(auto_now=True)
name = models.CharField(unique=True, max_length=settings.MAX_CHAR_COUNT, blank=False, null=False)
org = models.ForeignKey(Org, on_delete=models.CASCADE, blank=True, null=True)
You can work with .annotate(…) [Django-doc] to count the related objects in the same query:
from django.db.models import Count
class DomainList(generics.ListAPIView):
def get(self, request, format=None):
domains = Domain.objects.prefetch_related('org').annotate(
host_count=Count('host')
)
serializer = DomainSerializer(domains, many=True)
return Response(serializer.data)
In the serializer, you then simply retrieve the corresponding attribute:
class DomainSerializer(serializers.Serializer):
name = serializers.CharField(read_only=True)
org_name = serializers.CharField(source='org.name', read_only=True)
created = serializers.DateTimeField(read_only=True)
last_host_search = serializers.DateTimeField(read_only=True)
host_count = serializers.IntegerField(read_only=True)
This will make a query that looks like:
SELECT domain.*, org.*, COUNT(host.id)
FROM domain
LEFT OUTER JOIN org ON domain.org_id = org.id
LEFT OUTER JOIN host ON host.domain_id = domain.id
GROUP BY domain.id, org.id

How do I implement a workflow system that involves approval of a users in django rest framework

I have a leave model class that has the following definitions below. I would like to create some sort of work flow where after the employee applies for a leave after entering the required fields. He/She will be redirected to a pending url. which will show the details of the applied leave. Then there after will the supervisor approve or decline the leave. Any Ideas of how I can Implement this in the views using class based views? You will also see below of how I have Implemented this in the views.
class Leave(models.Model):
""" Vacation timesheet model """
LEAVE_STATUS_APPROVED = 1
LEAVE_STATUS_REJECTED = 2
LEAVE_STATUS_PENDING = 3
LEAVE_STATUS_CHOICES = (
(LEAVE_STATUS_APPROVED, 'approved'),
(LEAVE_STATUS_REJECTED, 'rejected'),
(LEAVE_STATUS_PENDING, 'pending'),
)
leave_id = models.AutoField(primary_key=True)
applicant = models.ForeignKey(
Employee, related_name='applicant', on_delete=models.CASCADE, null=True)
approver = models.ForeignKey(
Employee, related_name='approver', on_delete=models.CASCADE, null=True)
applied_on = models.DateTimeField(auto_now_add=True)
responded_on = models.DateTimeField(auto_now=True, null=True)
leave_type = models.ForeignKey(LeaveType, null=True)
approved = models.BooleanField(default=False)
rejected = models.BooleanField(default=False)
start_date = models.DateField()
return_date = models.DateField()
leave_status = models.CharField(max_length=80,
choices=LEAVE_STATUS_CHOICES,
default=LEAVE_STATUS_PENDING)
comment = models.TextField(max_length=200)
leave_subject = models.CharField(max_length=40)
leave_reason = models.TextField(max_length=200)
total_days = models.IntegerField(null=True)
class Meta:
db_table = 'LeaveApplication'
def __str__(self):
return str(self.employee) + "__" + self.leave_type + "__" + self.id
class LeaveApplyAPI(APIView):
"""
{ "applicant":1,
"approver":1,
"leave_type":1,
"leave_subject":"Sick Off",
"leave_reason":"Sick",
"start_date":"YY-MM-DD",
"return_date":"YY-MM-DD"
}
"""
lookup_field = 'pk'
# permission_classes = (permissions.DjangoObjectPermissions,)
serializer_class = ApplyLeaveSerializer
def total_days(self, start_date, return_date):
oneday = timedelta(days=1)
# convert str to datetime
start_date = datetime.strptime(start_date, '%Y-%m-%d')
return_date = datetime.strptime(return_date, '%Y-%m-%d')
total_days = 0
while (start_date <= return_date):
if not start_date.isoweekday() in (6, 7):
total_days += 1
start_date += oneday
return total_days
def get(self, request, format=None):
leaves = Leave.objects.all()
serializer = ApplyLeaveSerializer(leaves, many=True)
return Response(serializer.data)
def post(self, request, *args, **kwargs):
print(request.data)
start_date = request.data.get('start_date')
return_date = request.data.get('return_date')
total_days = self.total_days(start_date, return_date)
applicant = Employee.objects.get(id=request.data.pop('applicant'))
approver = Employee.objects.get(id=request.data.pop('approver'))
leave_type = LeaveType.objects.get(id=request.data.pop('leave_type'))
leave_subject = request.data.get('leave_subject')
leave_reason = request.data.get('leave_reason')
leave = Leave.objects.create(**request.data)
leave.total_days = total_days
leave.applicant = applicant
leave.approver = approver
leave.leave_type = leave_type
leave.leave_subject = leave_subject
leave.leave_reason = leave_reason
leave.save()
serializer = ApplyLeaveSerializer(leave)
return Response(serializer.data, status=status.HTTP_201_CREATED)
Separate your views into a LeaveApplyView and a LeaveApproveView and two corresponding serializers as well
You'll can have two serializers; the LeaveApplySerializer and LeaveApproveSerializer, with the fields set to read-only as applicable. For example (since I don't have the actual serializer definition, I am using my own:
This is an example of the apply serializer where the fields to be edited such as reason/type are editable, and other fields are read-only
class LeaveApplySerializer(serializers.ModelSerializer):
class Meta:
model = Leave
fields = (
'leave_id',
'applied_on',
.
.
.
'total_days',
)
read_only_fields = ( # Make the fields that the applicant can't edit read-only
'approver',
'approved',
'rejected',
'comment', # If this is an appoval field
)
This is an example of the approve serializer where the fields to be edited such as approved/rejected are editable, and other fields are read-only
class LeaveApproveSerializer(serializers.ModelSerializer):
class Meta:
model = Leave
fields = (
.
.
.
)
read_only_fields = ( # Make the fields that the appover can't edit read-only
'applicant',
'leave_type'
.
.
.
)
Finally, flesh out two separate views for approvals and applications; or dynamically select the right serailizer based on the user/action type for the view.
You can then use a custom permission_class on the LeaveApproveView to only allow the Approver to edit this model
class LeaveApproverPermission(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
"""
Return `True` if the user us an approver for the leave.
"""
return request.user == obj.approver.user
One suggestions: It appears that the Leave and Approvals are fairly non-overlapping and you might stand to benefit from separating them at a model level. Why not have two models:
class Leave and class LeaveApproval that have a OneToOneField mapping between them?

django model inheritance & casting to subtype in a view

It's a sort of cms type application
I have an article model and some specializations in models.py
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
def __unicode__(self):
return self.title
class Artist(Article):
website = models.URLField(max_length=200,blank=True)
class Venue(Article):
location = models.CharField(max_length=150)
map_link = models.URLField(max_length=200,blank=True)
class Event(Article):
time = models.DateTimeField()
venue = models.ForeignKey(Venue)
performers = models.ManyToManyField(Artist)
I want to render these in different ways depending on the value of article.display but when I call
articles.objects.all()
I still need the extra attributes form the subclasses so I wrote
#views.py
def castToSubClass(article):
try:
return Artist.objects.get(article_ptr_id = article.id)
except:
try:
return Event.objects.get(article_ptr_id = article.id)
except:
try:
return Venue.objects.get(article_ptr_id = article.id)
except:
return article
def index(request):
carousel = [castToSubClass(article) for article in Article.objects.filter(display='C']
marketing = [castToSubClass(article) for article in Article.objects.filter(display='M'[:3]]
featurettes = [castToSubClass(article) for article in Article.objects.filter(display='F']
return render_to_response('frontpage.html',
{
'carousel': carousel,
'marketing':marketing,
'featurettes': featurettes
})
to turn them all in the appropriate subclass object, this apart from seeming clunky seems to mean I'm hitting the database twice for every (or nearly every) item in the queryset.
Is there a way to do this in the initial calls to the manager instead?
Thanks.
Use one model to store everything, and add a field to distinguish the article type, so that you can render different look for every type combine with display in the template(Like tumblr do).
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
ARTICLE_TYPE_CHOICES = (
('artist', 'Artist'),
('venue', 'Venue'),
('event', 'Event'),
)
type = models.CharField(max_length=32, choices = ARTICLE_TYPE_CHOICES)
website = models.URLField(max_length=200,blank=True, null=True)
location = models.CharField(max_length=150, blank=True, null=True)
map_link = models.URLField(max_length=200,blank=True, null=True)
time = models.DateTimeField(null=True)
venue = models.ForeignKey('self', null=True)
performers = models.ManyToManyField('self', null=True)
def __unicode__(self):
return self.title
#views.py
def index(request):
carousel = Article.objects.filter(display='C')
marketing = Article.objects.filter(display='M')
featurettes = Article.objects.filter(display='F')
return render_to_response('frontpage.html',{'carousel': carousel, 'marketing':marketing, 'featurettes': featurettes})

Categories

Resources