django api using generic views for deleting multiple objects - django

i'm trying to use django generic view. and i want to be able to delete multiple objects at the same time using the same view.for example delete all the 'femail' Employees in my model.
i used the following code:
from ..models import Employee
from . import serializer
from rest_framework import generics, status
from rest_framework.response import Response
from django.shortcuts import get_list_or_404, get_object_or_404
class EmployeeDeleteandUpdate(generics.UpdateAPIView):
queryset = Employee.objects.filter(gender__startswith='femail')
serializer_class = serializer.PostSerializer
def delete(self, request, *args, **kwargs):
myobj = get_object_or_404(Employee, gender=kwargs['gender'])
myobj.delete()
return Response("Femails deleted", status=status.HTTP_204_NO_CONTENT)
and heres my url code:
path('mydel/<str:gender>/', view.EmployeeDeleteandUpdate.as_view()),
and also my model:
class Employee(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
gender = models.CharField(max_length=10)
national_code = models.CharField(max_length=11)
personal_code = models.CharField(max_length=15)
phone_number = models.CharField(max_length=11)
address = models.CharField(max_length=50)
married = models.BooleanField()
age = models.IntegerField()
wage = models.IntegerField()
def __str__(self):
return self.first_name
but when i use delete method with following url in my django rest framework:
http://127.0.0.1:8000/mydel/femail/
i get this error:
client.models.Employee.MultipleObjectsReturned: get() returned more
than one Employee -- it returned 2!
can somebody help me with this problem please??

The get_object_or_404 method only gets 1 object from the table so it is compulsory the record will be unique in the table. Otherwise, it gives an error.
Please try this code:
def delete(self, request, *args, **kwargs):
employees = Employee.objects.filter(gender=kwargs['gender'])
if employees.count() > 0:
employees.delete()
return Response("Femails deleted", status=status.HTTP_204_NO_CONTENT)
return Response("Unable to find the femails.", status=status.HTTP_404_OK)
In this code snippet, I am filtering the result based on kwargs['gender'] and then count its objects if greater than one then delete it using the loop.

Related

Suggestions for returning relational data in Django REST Framework

I'm new to Django/Django REST FW (and new to this community). I've spent a lot of time reading the documentation but I'm spinning my wheels at this point. I apologize in advance for being so long-winded here.
My back end DB is Postgres. I've got 3 Models, User, Item and ShoppingList. I need Item to contain a description (the item_name field) and its location. The user will select an item and add it to the ShoppingList for that day. The idea is that the user will then "check off" the item once acquired and it'll be "removed" from the view of the ShoppingList.
Here is where I'm having trouble: I don't want to duplicate the item_name and item_location fields in the shopping_list table, but I need to display those fields in the view of the shopping list (shopping_lists.py).
There is a one-to-many relationship between Item and ShoppingList respectively. The Item object is considered a "master items table" that stores descriptions and locations for each item. The ShoppingList object holds a temporary list of these "master items". I need a queryset that contains all fields from ShoppingList and 2 or more fields from Item.
I think this would be what Django REST FW considers a Reverse Relationship. I've tried a variety of changes to my Serialzer(s) and Models (including adding the Item Serializer to the ShoppingList Serializer) and gotten a variety of errors.
models/item.py:
from django.db import models
from django.contrib.auth import get_user_model
class Item(models.Model):
item_name = models.CharField(max_length=50, db_index=True)
item_location = models.CharField(max_length=10, blank=True, db_index=True)
item_class = models.CharField(max_length=20, blank=True)
# This is a relationship with User model
shopper_id = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE
)
def __str__(self):
return f"item_name: {self.item_name}, item_location: {self.item_location}, shopper_id: {self.shopper_id}"
models/shopping_list.py:
from django.db import models
from django.contrib.auth import get_user_model
from .item import Item
class ShoppingList(models.Model):
item_num = models.ForeignKey(
'Item',
on_delete=models.DO_NOTHING # we don't want to delete the item from the "master" item list, just from this shopping list
)
# This is a relationship with user model.
shopper_id = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE # ...but we do want to delete the item if the user goes away as items are user-specific
)
item_qty = models.PositiveIntegerField()
item_complete = models.BooleanField(default=False)
added_on = models.DateField(auto_now=True)
# setting list_num to blank=True for this version
list_num = models.PositiveIntegerField(blank=True)
def __str__(self):
return f"item_num: {self.item_num}, shopper_id: {self.shopper_id}, item_qty: {self.item_qty}, item_complete: {self.item_complete}"
serializers/item.py:
from rest_framework import serializers
from ..models.item import Item
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('id', 'item_name', 'item_location', 'item_class', 'shopper_id')
serializers/shopping_list.py:
from rest_framework import serializers
from ..models.shopping_list import ShoppingList
class ShoppingListSerializer(serializers.ModelSerializer):
class Meta:
model = ShoppingList
fields = ('id', 'item_num', 'shopper_id', 'item_qty', 'item_complete', 'added_on', 'list_num')
Getting ERROR AttributeError: Manager isn't accessible via ShoppingList instances when I execute the GET method in class ShoppingListItemView in views/shopping_lists.py below:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from rest_framework.exceptions import PermissionDenied
from ..models.shopping_list import ShoppingList
from ..serializers.shopping_list import ShoppingListSerializer
from ..models.item import Item
from ..serializers.item import ItemSerializer
class ShoppingListsView(APIView):
def get(self, request, list_num):
shopping_items = ShoppingList.objects.filter(shopper_id=request.user.id)
shopping_list_items = shopping_items.filter(list_num=list_num)
data = ShoppingListSerializer(shopping_list_items, many=True).data
return Response(data)
def post(self, request):
request.data['shopper_id'] = request.user.id
list_item = ShoppingListSerializer(data=request.data, partial=True)
if list_item.is_valid():
list_item.save()
return Response(list_item.data, status=status.HTTP_201_CREATED)
else:
return Response(list_item.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, list_num):
shopping_items = ShoppingList.objects.filter(shopper_id=request.user.id)
shopping_list_items = shopping_items.filter(list_num=list_num)
response_data = shopping_list_items.delete()
return Response(response_data, status=status.HTTP_204_NO_CONTENT)
class ShoppingListsAllView(APIView):
def get(self, request):
shopping_items = ShoppingList.objects.filter(shopper_id=request.user.id)
data = ShoppingListSerializer(shopping_items, many=True).data
return Response(data)
class ShoppingListItemView(APIView):
def get(self, request, pk):
list_item = get_object_or_404(ShoppingList, pk=pk)
if request.user != list_item.shopper_id:
raise PermissionDenied('Unauthorized, this item belongs to another shopper')
else:
list_entry = list_item.objects.select_related('Item').get(id=pk)
print(list_entry)
data = ShoppingListSerializer(list_item).data
return Response(data)
def delete(self, request, pk):
list_item = get_object_or_404(ShoppingList, pk=pk)
if request.user != list_item.shopper_id:
raise PermissionDenied('Unauthorized, this item belongs to another shopper')
else:
list_item.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
def patch(self, request, pk):
list_item = get_object_or_404(ShoppingList, pk=pk)
if request.user != list_item.shopper_id:
raise PermissionDenied('Unauthorized, this item belongs to another shopper')
else:
request.data['shopper_id'] = request.user.id
updated_list_item = ShoppingListSerializer(list_item, data=request.data, partial=True)
if updated_list_item.is_valid():
updated_list_item.save()
return Response(updated_list_item.data)
else:
return Response(updated_item.errors, status=status.HTTP_400_BAD_REQUEST)
if you want to display only a few properties of an item in your ShoppingList you can use the SerializerMethodField method in your serializer
this would work as -
class ShoppingListSerializer(serializers.ModelSerializer):
itemProperty1 = serializers.SerializerMethodField()
itemProperty2 = serializers.SerializerMethodField()
class Meta:
model = ShoppingList
fields = ('id', "itemProperty1", "itemProperty2", 'more_fields')
def get_itemProperty1(self, instance):
return instance.item.anyPropertyOfItem if instance.item else ''
def get_itemProperty2(self, instance):
return instance.item.anyPropertyOfItem if instance.item.else ''
anyPropertyOfItem can be anything from item models.
Setting your serializer this way, your ShoppingList view will automatically show 2 new fields.
or you can also define read only fields with the help of #property in models to get the required field.
If you want to display all the properties of the item in the ShoppingList view, you can write here, will edit my answer. There you need to use related_name and get the item serializer in Shoppinglist serializer as the extra field.
For reverse relationship you should use related_name when defining the model or using the suffix _set.
The related_name attribute specifies the name of the reverse relation
from the User model back to your model. If you don't specify a
related_name, Django automatically creates one using the name of your
model with the suffix _set
Copied from What is related_name used for? by Wogan

Show list in django without html file?

I have 2 models but I want to show the name of the artist in my output
class Musician(models.Model):
name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
name = models.CharField(max_length=100)
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
num_stars = models.IntegerField()
I want to show musician name by HttpResponse function
class Musician_list(Musician, Album):
def get(self, request):
query = Musician.objects.all().values_list("name").order_by("name")
return HttpResponse(query)
but this code doesn't show anything - please help me.
from django.http import JsonResponse
def get(self, request):
names = Musician.objects.values_list("name",flat=True)
return JsonResponse(names, safe=False)
You can read more about JsonResponse from the doc here
Your Usecase

How we can make filtered query in schema.py in graphene-django project without using Relay feature?

I am new to back-end programming especially in graphene-django.
my question is how can we create filtered query in schema.py in graphene-django project without using Relay feature? i saw this before but i don't want to use Relay feature. rather than i want use a filter, but i don't know how?? now my models.py and schema.py look-like these:
*models.py
# shoes_store/ingredients/models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=50)
notes = models.TextField(default='')
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=300)
descreption = models.TextField(default='')
price = models.CharField(max_length=50, default='')
imageURL = models.TextField(default='')
category= models.ForeignKey(Category,on_delete=models.CASCADE)
def __str__(self):
return self.name
and schema.py:
import graphene
from graphene_django.types import DjangoObjectType
from shoes_store.ingredients.models import Category, Product
class CategoryType(DjangoObjectType):
class Meta:
model = Category
class ProductType(DjangoObjectType):
class Meta:
model = Product
class Query:
#===========================
# product
products = graphene.List(ProductType)
product = graphene.Field(ProductType,product_id=graphene.ID())
def resolve_products(self, info, **kwargs):
# Querying a list
return Product.objects.all()
def resolve_product(self, info, product_id):
# Querying a single user
return Product.objects.get(pk=product_id)
#===========================
# product_category
categories = graphene.List(CategoryType)
category = graphene.Field(CategoryType,category_id=graphene.ID())
def resolve_categories(self, info, **kwargs):
# Querying a list
return Category.objects.all()
def resolve_category(self, info, category_id):
# Querying a single user
return Category.objects.get(pk=category_id)
the best solution is look-like this if you don't want use Relay.
you can change your schema.py similar to:
import graphene
from graphene_django.types import DjangoObjectType
from shoes_store.ingredients.models import Category, Product
from django.db.models import Q
class CategoryType(DjangoObjectType):
class Meta:
model = Category
class ProductType(DjangoObjectType):
class Meta:
model = Product
class Query:
#===========================
# product
products = graphene.List(ProductType,name=graphene.String(),category_id=graphene.ID())
product = graphene.Field(ProductType,product_id=graphene.ID())
def resolve_products(self, info, name=None,category_id=None, **kwargs):
# Querying a list
if name:
filter = (
Q(name__icontains=name) |
Q(descreption__icontains=name)
)
return Product.objects.filter(filter)
#
if category_id:
filter = (
Q(category_id__exact=category_id)
)
return Product.objects.filter(filter)
#
return Product.objects.all()
def resolve_product(self, info, product_id):
# Querying a single user
return Product.objects.get(pk=product_id)
#===========================
# product_category
categories = graphene.List(CategoryType)
category = graphene.Field(CategoryType,category_id=graphene.ID())
def resolve_categories(self, info, **kwargs):
# Querying a list
return Category.objects.all()
def resolve_category(self, info, category_id):
# Querying a single user
return Category.objects.get(pk=category_id)
now you can use different queries in your "http://127.0.0.1:8000/graphql" address. fore example you can use:
query{
products{
id
name
price
}
}
or even:
query{
products(categoryId:1){
id
name
price
}
}
or
query{
products(name:"Men's boots"){
id
name
price
}
}

Django v1.10: Getting a JSON of all `Country` models stored in the model `Continent`

I have the following models:
from django.db import models
MNL = 50
MCL = 5
class Continent(models.Model):
"""
Fields
"""
name = models.CharField("name", max_length=MNL, unique=True)
code = models.CharField("code", max_length=MCL, default="", unique=True)
class Meta:
ordering = ['name']
"""
Methods
"""
def __str__(self):
return "%s, %s" % (self.name, self.code)
class Country(models.Model):
"""
Fields
"""
name = models.CharField("name", max_length=MNL, unique=True)
capital = models.CharField("capital", max_length=MNL)
code = models.CharField("code", max_length=MCL, default="", unique=True)
population = models.PositiveIntegerField("population")
area = models.PositiveIntegerField("area")
continent = models.ForeignKey(Continent, on_delete=models.CASCADE,
related_name="countries")
class Meta:
ordering = ['name']
"""
Methods
"""
def __str__(self):
return "%s, %s" % (self.name, self.code)
I need to be able to retrieve 2 things in JSON(P):
individual Country's capital, population and area fields in the form {"area":<area>,"population":<population>,"capital":<capital_name>} and
in the case of a Continent, all of the countries in that continent in the form {"code1":"name1", "code2":"name2",...}
I've tried implementing the following views to achieve this:
from django.http import HttpResponse, Http404, JsonResponse
from django.forms.models import model_to_dict
import json
from .models import Continent, Country
def continent_json(request, continent_code):
""" Write your answer in 7.2 here. """
try:
print("CONTINENT QuerySet: ", Continent.objects.filter(
code__exact=continent_code).values("countries"))
continent_data = json.dumps( list(Continent.objects.filter(
code__exact=continent_code).values("countries") ) )
print("CONTINENT JSON: ",continent_data)
except Continent.DoesNotExist:
raise Http404("Requested continent does not exist.")
# If JSONP
if "callback" in request.GET:
continent_data = "{}({})".format(
request.GET["callback"],
continent_data
)
return HttpResponse(continent_data)
# Normal JSON
return HttpResponse(continent_data, content_type="application/json")
def country_json(request, continent_code, country_code):
""" Write your answer in 7.2 here. """
try:
#print("COUNTRY_OBJECT: "Country.objects.filter(code__exact=country_code).values())
print("MODEL_LIST: ",list(Country.objects.filter(code__exact=country_code).values("capital","population","area")))
country_data = json.dumps( list(Country.objects.filter(
code__exact=country_code).values("code","name") ) )
print("COUNTRY DATA: ", country_data)
except Country.DoesNotExist:
raise Http404("Requested country does not exist.")
# If JSONP
if "callback" in request.GET:
country_data = "{}({})".format(
request.GET["callback"],
country_data
)
return HttpResponse(country_data)
# Normal JSON
return HttpResponse(country_data, content_type="application/json")
However, this is not producing the results I want: the data is not actually coming back as JSON(P), but as either a dict or a list. This is a lot of code to shift through, but I'm at my wits end here.
What am I doing wrong?
From what you explained on chat:
You need to change your views to something like this
country_data = json.dumps(dict(Country.objects.filter(
code__exact=country_code).values("code","name")[0])))
and for continent view:
continent = Continent.objects.get(code__exact=continent_code)
country_data = json.dumps(dict(continent.countries.values_list('code', 'name')))

Using a SELECT field for a OneToMany field

let's say I've the following very simple models:
class Customer(models.Model):
name = models.CharField(max_length=50)
class Probe(models.Model):
OwnerInfo = models.CharField(max_length=50)
comments = models.CharField(max_length=50)
customer = models.ForeignKey(Customer, null=True, blank=True)
I've been able to add an InLine to the Admin gui, but I'd like to use a SELECT component, so I can just select several Probes and assign them to the Customer. From this question:
one-to-many inline select with django admin
I know thanks to Luke's answer (last one) that I should create a custom Form and assign it to my ModelAdmin.form but I can not wonder how to tie it all together to make it work.
May anyone help?
Thanks a lot in advance.
OK, I came a step further, and now I've the field added to the Form, like this:
from django.contrib import admin
from django import forms
from web_gui.models import Probe, Customer, Firmware
class CustomerForm(forms.ModelForm):
probes = forms.ModelMultipleChoiceField(queryset=Probe.objects.all())
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['probes'].initial = [p.pk for p in Probe.objects.filter(customer_id=self.instance.pk)]
class Meta:
model = Customer
class CustomerAdmin(admin.ModelAdmin):
form = CustomerForm
admin.site.register(Probe)
admin.site.register(Customer, CustomerAdmin)
admin.site.register(Firmware)
but the initial values specified through "initial" are not being selected. What's wrong now? I assume that next will be to override the save() method to set the Probes on the Customer, am I right?
This is the best solution I've came up with. Let me know if there is any other better way of achieving this:
from django.contrib import admin
from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from web_gui.models import Probe, Customer, Firmware
class CustomerForm(forms.ModelForm):
probes = forms.ModelMultipleChoiceField(queryset = Probe.objects.all(), required=False)
probes.widget = FilteredSelectMultiple("Probes",False,attrs={'rows':'10'})
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['probes'].initial = [p.pk for p in Probe.objects.filter(customer_id=self.instance.pk)]
def save(self, force_insert=False, force_update=False, commit=True):
c = super(CustomerForm, self).save(commit=False)
c.probe_set = self.cleaned_data['probes']
c.save()
return c
class Meta:
model = Customer
class CustomerAdmin(admin.ModelAdmin):
form = CustomerForm
admin.site.register(Probe)
admin.site.register(Customer, CustomerAdmin)
admin.site.register(Firmware)