'm building a small webstore , in the product page i put the order form using FormMixin and TemplateView, when i submit the order i get a " null value in column "customer_id" of relation "products_order" violates not-null constraint
DETAIL: Failing row contains (21, null)." error :
models.py
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
nominal_price = models.PositiveIntegerField(verbose_name='prix normal',)
reduced_price = models.PositiveIntegerField(blank=True, null=True)
quantity = models.PositiveIntegerField(default=10)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
photo = models.ImageField(upload_to="img/products/", default="img/products/user_default.png")
def __str__(self):
return self.name
class Customer(models.Model):
full_name = models.CharField(max_length=150)
address = models.CharField(max_length=1500, null=True)
phone = models.IntegerField()
city = models.CharField(max_length=100)
email = models.EmailField(null=True)
def __str__(self):
return self.full_name
class Order (models.Model):
product = models.ManyToManyField(Product, through='OrderProduct')
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
class OrderProduct(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
views.py :
class ProductDetailView(FormMixin, TemplateView):
model = Product
template_name = 'product.html'
form_class = OrderForm
def get_success_url(self):
return reverse('index')
def post(self, request, *args, **kwargs):
context = self.get_context_data()
form = OrderForm(request.POST)
if context['form'].is_valid():
product = get_object_or_404(Product, name=self.kwargs['product_name'])
customer = form.save()
instance = Order.objects.create(customer=customer)
instance.product.set(product)
return super(TemplateView, self)
def get_context_data(self, **kwargs):
context = super(ProductDetailView, self).get_context_data(**kwargs)
context['product'] = Product.objects.get(name=self.kwargs['product_name'])
context['form'] = self.get_form()
return context
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.ProductListView.as_view(), name='index'),
path ('<str:product_name>/', views.ProductDetailView.as_view(), name='product'),
path('categories/', views.CategoryListView.as_view(), name='categories'),
path('add_category', views.AddCategoryView.as_view(), name='add_category'),
path('add_product/', views.AddProductView.as_view(), name='add_product'),
path('categories/<str:category_name>/', views.CategoryProductsView.as_view(), name='category_products'),
]
Traceback
Traceback (most recent call last):
File "D:\Python\Django\Django projects\Store\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "D:\Python\Django\Django projects\Store\venv\lib\site-packages\django\utils\deprecation.py", line 119, in __call__
response = self.process_response(request, response)
File "D:\Python\Django\Django projects\Store\venv\lib\site-packages\django\middleware\clickjacking.py", line 26, in process_response
if response.get('X-Frame-Options') is not None:
AttributeError: 'super' object has no attribute 'get'
Related
views.py
class ReviewList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Review.objects.all()
serializer_class = ReviewSerializer
def get(self,request,*args,**kwargs):
return self.list(request, *args, **kwargs)
def post(self,request,*args,**kwargs):
return self.create(request, *args, **kwargs)
models.py
class Review(models.Model):
rating = models.PositiveIntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)])
description = models.CharField(max_length=200, null=True)
created = models.DateTimeField(auto_now_add=True)
update = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
watchlist = models.ForeignKey(WatchList, on_delete=models.CASCADE, related_name='reviews')
def __str__(self) -> str:
return str(self.rating) + ' - ' + self.watchlist.title
urls.py
urlpatterns = [
path('list/', WatchListAV.as_view(), name='movie-list'),
path('<int:pk>', MovieDetailsAV.as_view(),name='movie-details'),
path('stream/',StreamPlatformAV.as_view(),name='stream-list'),
path('stream/<int:pk>', StreamDetailAV.as_view(), name="stream-detail"),
path('review/', ReviewList.as_view(),name='review-list'),
]
serializers.py
class ReviewSerializer(serializers.Serializer):
class Meta:
model = Review
fields = '__all__'
the list of reviews return empty
as attached in photo the list of reviews is empty, im new to django cant figure it out
When creating serializers for a model you should subclass ModelSerializer
class ReviewSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = '__all__'
I have a Cart model and Cartserializers. I am trying to do that is if cart defects exist in the cart and then update the cart by increasing the quantity of cart. I tried a lot to do this. But it raises an error every time this time is The response content must be rendered before it can be iterated over.
Here is my code :)
views.py*
class CartViewSet(viewsets.ModelViewSet):
serializer_class = CartSerializer
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 Cart.objects.all()
raise PermissionDenied()
raise PermissionDenied()
raise PermissionDenied()
filter_backends = [DjangoFilterBackend]
filterset_fields = ['date_created', 'user']
#action(detail=False)
def count(self, request):
queryset = self.filter_queryset(self.get_queryset())
count = queryset.count()
content = {'count': count}
return Response(content)
def create(validated_data, get):
quantity, created = Cart.objects.update_or_create(
user = validated_data.get('user', None),
defects=validated_data.get('defects', None),
defaults={'quantity': validated_data.get('quantity' + str(1), None)})
return quantity
if quantity is created.create:
return Response ({
'status' : True,
"detail" : "created"
})
if quantity is created.update:
return Response ({
'status' : True,
"detail" : "updated"
})
models.py
from django.db import models
from accounts.models import User, SubCategory
# Create your models here.
class Cart(models.Model):
user = models.ForeignKey('accounts.User', related_name="carts", null=True, on_delete=models.SET_NULL)
quantity = models.IntegerField(default=1)
service = models.ForeignKey('accounts.SubCategory',null=True, on_delete=models.SET_NULL)
defects = models.ForeignKey('Defects',null=True, on_delete=models.SET_NULL)
price = models.IntegerField(default=False)
date_created = models.DateTimeField(auto_now_add=True)
total = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.user.username
serializers.py
from rest_framework import serializers
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = Cart
fields = ['id','url', 'user', 'service', 'defects', 'date_created', 'quantity' , 'price', 'total']
Your get_queryset() method must return a queryset!
I have problem with saving files to my server. I need to upload and save files, but id doesn't work for me. I can send file from my UI to my rest api, but i am not able to save the files.
My Models
fs = FileSystemStorage(location='/media/attachments/')
...
class TicketLog(models.Model):
ticket = models.ForeignKey(Ticket, on_delete=models.DO_NOTHING, related_name='ticket_log')
created_date = models.DateTimeField(auto_now=False, auto_now_add=True)
created_by = models.ForeignKey(
User,
on_delete=models.DO_NOTHING,
related_name='ticketlog_creator')
note = models.TextField()
class Meta:
ordering = ['pk']
def __str__(self):
return self.note
class TicketFiles(models.Model):
ticketlog = models.ForeignKey(TicketLog, on_delete=models.CASCADE, related_name='log_file', blank=True, null=True)
attachment = models.FileField(upload_to='attachments', storage=fs)
class UploadWithFile(APIView):
parser_classes = [MultiPartParser, ]
def post(self, request):
content = request.data['file']
data = json.loads(request.data['data'])
queue = Queue.objects.get(pk=data['queue']['id'])
priority = Priority.objects.get(pk=data['priority']['id'])
status = Status.objects.get(pk=data['status']['id'])
created_by = User.objects.get(pk=data['ticket_log'][0]['created_by_id'])
ticket_data = Ticket(
name=data['name'],
priority=priority,
status=status,
queue=queue,
created_date=datetime.datetime.now(),
created_by=created_by
)
ticket_data.save()
log_data = TicketLog(
ticket=ticket_data,
created_date=datetime.datetime.now(),
created_by=created_by,
note=data['ticket_log'][0]['note']
)
log_data.save()
file_data = TicketFiles(
ticketlog=log_data
)
file_data.attachment.save(content.name, content)
file_data.save()
return HttpResponse(content)
It seems that everything works fine and the database is updated correctly, but the files are not saved on server.
An example using rest_framework.parsers ==>> FileUploadParser:
url.py:
urlpatterns = +[
url(r'^docs/$', views.DocumentView.as_view(), name='docs'),
]
models.py
class Document(models.Model):
DOC_CATEGORY = (
('profile_pic', 'Profile_Picture'),
)
class Meta:
ordering = ['uploaded_at']
uploaded_at = models.DateTimeField(auto_now_add=True)
file = models.FileField(blank=False, null=False)
# description
remark = models.CharField(max_length=200, blank=True, null=True)
user = models.ForeignKey(User, blank=True, on_delete=models.DO_NOTHING,)
category = models.CharField(
'Document category',
max_length=64,
choices=DOC_CATEGORY,
default='profile_pic')
def __str__(self):
return self.file.name
serializers.py
class DocumentSerializer(serializers.ModelSerializer):
class Meta():
model = Document
fields = ('file', 'remark', 'uploaded_at', 'user', 'category')
and last views.py:
from rest_framework.parsers import FileUploadParser
class DocumentView(APIView):
http_method_names = ['get', 'post']
model = Document
# fields = ['upload', ]
success_url = reverse_lazy('/')
parser_class = (FileUploadParser,)
# permission_classes = [DocumentViewPerm, ]
# allow any for the example!!!
permission_classes = [AllowAny, ]
def get_object(self, pk):
return serializers.serialize(
'json', list(Document.objects.filter(pk=pk))
)
def get(self, request, pk=None, format=None):
category = request.query_params.get('category', None)
if request.query_params.get('pk'):
return HttpResponse(
self.get_object(pk=request.query_params.get('pk'),
content_type="application/json")
return HttpResponse(self.get_object(request.user.pk),
content_type="application/json")
def post(self, request, *args, **kwargs):
file_serializer = DocumentSerializer(data=request.data)
########################################################
# when uploading keep these headers- no content type !!!
# headers = {'Authorization': '{}'.format(token), 'Accept':
# 'application/json'}
########################################################
if file_serializer.is_valid():
file_serializer.save(user=self.request.user)
# save all fields
# remark # category
remark = request.data.get('remark')
category = request.data.get('category')
return Response(file_serializer.data,
status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
#
EXAMPLE upload a file, open python cmd line
import requests, json
# no content type in headers !!!
headers = {'Accept': 'application/json',
'Authorization': "TOKEN"}
with open('pathtofile', 'rb') as f:
r = requests.post('http://MachineIP/docs/', files={'file': f}, data={'remark': 'my remark'}, headers=headers)
You do not have to write your custom code. Using ModelSerializer, you can achieve what you want.
class TicketFilesSerializer(serializer.ModelSerializer):
class Meta:
model = TicketFiles
fields = '__all__'
You can add other fields that you want according to your requirement.
In your API view,
class YourView(generics.GenericApiView):
serializer_class = TicketFilesSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(request.data)
if serializer.is_valid():
serializer.save()
You have to send data in multipart format.
I would like to get access to fields of the InlineFormSet for consumption into the View.
Here is an example based on https://django-extra-views.readthedocs.io/en/latest/views.html#createwithinlinesview-and-updatewithinlinesview:
from extra_views import InlineFormSet, CreateWithInlinesView,
class ItemsInline(InlineFormSet):
model = Item
class TagsInline(InlineFormSet):
model = Tag
class OrderCreateView(CreateWithInlinesView):
model = Order
inlines = [ItemsInline, TagsInline]
def get_success_url(self):
return self.object.get_absolute_url()
How do I expose the InlineFormSet fields in the get_context_data() and forms_valid() methods?
Warning: Code below fails!
class OrderCreateView(CreateWithInlinesView):
[... see above ...]
def get_context_data(self, **kwargs):
context = super(OrderCreateView, self).get_context_data(**kwargs)
if self.request.POST:
context['items'] = ItemsInline(self.request.POST)
context['tags'] = TagsInline(self.request.POST)
else:
context['items'] = ItemsInline()
context['tags'] = TagsInline()
return context
def forms_valid((self, form, inlines):
[...]
return super(OrderCreateView, self).forms_valid(form, inlines)
I reproduced your example with this models:
STATUS_CHOICES = (
(0, 'Placed'),
(1, 'Charged'),
(2, 'Shipped'),
(3, 'Cancelled'),
)
class Order(models.Model):
name = models.CharField(max_length=255)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
action_on_save = models.BooleanField(default=False)
class Item(models.Model):
item_name = models.CharField(max_length=255)
sku = models.CharField(max_length=13)
price = models.DecimalField(decimal_places=2, max_digits=12, db_index=True)
order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
status = models.SmallIntegerField(default=0, choices=STATUS_CHOICES, db_index=True)
date_placed = models.DateField(default=now, null=True, blank=True)
def __unicode__(self):
return '%s (%s)' % (self.item_name, self.sku)
class Tag(models.Model):
tag_name = models.CharField(max_length=255)
content_type = models.ForeignKey(ContentType, null=True, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(null=True)
content_object = GenericForeignKey('content_type', 'object_id')
def __unicode__(self):
return self.tag_name
Urls:
from django.conf.urls import url
from .views import OrderCreateView, OrderUpdateView
urlpatterns = [
url(r'^inlines/new/$', OrderCreateView.as_view()),
url(r'^inlines/(?P<pk>\d+)/$', OrderUpdateView.as_view()),
]
Forms:
from django import forms
from .models import Order, Item
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['name']
def save(self, commit=True):
instance = super(OrderForm, self).save(commit=commit)
if commit:
instance.action_on_save = True
instance.save()
return instance
class ItemForm(forms.ModelForm):
flag = forms.BooleanField(initial=True)
class Meta:
model = Item
fields = ['item_name', 'sku', 'price', 'order', 'status']
Views:
from django.contrib.contenttypes.models import ContentType
from extra_views import InlineFormSet, CreateWithInlinesView, UpdateWithInlinesView
from extra_views.generic import GenericInlineFormSet
from .forms import OrderForm
from .models import Item, Order, Tag
class ItemsInline(InlineFormSet):
model = Item
fields = ['item_name', 'sku', 'price', 'order', 'status']
class TagsInline(GenericInlineFormSet):
model = Tag
fields = ['tag_name']
class OrderCreateView(CreateWithInlinesView):
model = Order
fields = ['name']
context_object_name = 'order'
inlines = [ItemsInline, TagsInline]
template_name = 'extra_views/order_and_items.html'
def get_success_url(self):
return '/inlines/%i' % self.object.pk
class OrderUpdateView(UpdateWithInlinesView):
model = Order
form_class = OrderForm
inlines = [ItemsInline, TagsInline]
template_name = 'extra_views/order_and_items.html'
def get_success_url(self):
return ''
In OrderCreateView you cannot read Tag and Item records in the
get_context_data method because they haven't been created.
In OrderCreateView you can read all records after the forms_valid
method as usual.
In OrderUpdateView you can read all records in the
get_context_data method like in the forms_valid method.
It looks like this:
class OrderCreateView(CreateWithInlinesView):
# ...
def get_context_data(self, **kwargs):
data = super(OrderCreateView, self).get_context_data(**kwargs)
from pprint import pprint
pprint(self.request.POST) # there is only post data here
return data
def forms_valid(self, form, inlines):
instance = super(OrderCreateView, self).forms_valid(form, inlines)
ct = ContentType.objects.get_for_model(self.model)
print('all items', [item.item_name for item in self.object.items.all()]) # items
print('all tags', [tag.tag_name for tag in
TagsInline.model.objects.filter(content_type=ct, object_id=self.object.id)]) # tags
return instance
class OrderUpdateView(UpdateWithInlinesView):
# ...
def get_context_data(self, **kwargs):
context = super(OrderUpdateView, self).get_context_data(**kwargs)
ct = ContentType.objects.get_for_model(self.model)
print('all items', [item.item_name for item in self.object.items.all()]) # items
print('all tags', [tag.tag_name for tag in
TagsInline.model.objects.filter(content_type=ct, object_id=self.object.id)]) # tags
return context
I have a slug field for a model that I would like returned in the object representation but NOT as part of the form input in the browsable API. It is generated by a slugify method on the model.
When I mark it as read only in it's ModelSerializer by adding it to Meta using read_only_fields=('slug',) trying to add new fields in the browseable api form yields "This field is required."
The serializer for reference is below:
class CategorySerializer(serializers.HyperlinkedModelSerializer):
slug = serializers.SlugField(read_only=True, required=False)
def to_representation(self, obj):
self.fields['children'] = CategorySerializer(obj, many=True, read_only=True)
return super(CategorySerializer, self).to_representation(obj)
class Meta:
model = Category
fields = ('pk', 'url', 'title', 'slug', 'parent', 'children', 'active', 'icon')
read_only_fields = ('children','slug',)
What is a simple solution to show the field in the representation and not the browseable api form given the above?
For reference, here is my model:
#python_2_unicode_compatible
class CategoryBase(mptt_models.MPTTModel):
parent = mptt_fields.TreeForeignKey( 'self', blank=True, null=True, related_name='children', verbose_name=_('parent'))
title = models.CharField(max_length=100, verbose_name=_('name'))
slug = models.SlugField(verbose_name=_('slug'), null=True)
active = models.BooleanField(default=True, verbose_name=_('active'))
objects = CategoryManager()
tree = TreeManager()
def save(self, *args, **kwargs):
"""
While you can activate an item without activating its descendants,
It doesn't make sense that you can deactivate an item and have its
decendants remain active.
"""
if not self.slug:
self.slug = slugify(self.title)
super(CategoryBase, self).save(*args, **kwargs)
if not self.active:
for item in self.get_descendants():
if item.active != self.active:
item.active = self.active
item.save()
def __str__(self):
ancestors = self.get_ancestors()
return ' > '.join([force_text(i.title) for i in ancestors] + [self.title, ])
class Meta:
abstract = True
unique_together = ('parent', 'slug')
ordering = ('tree_id', 'lft')
class MPTTMeta:
order_insertion_by = 'title'
class Category(CategoryBase):
icon = IconField(null=True, blank=True)
order = models.IntegerField(default=0)
#property
def short_title(self):
return self.title
def get_absolute_url(self):
"""Return a path"""
from django.core.urlresolvers import NoReverseMatch
try:
prefix = reverse('categories_tree_list')
except NoReverseMatch:
prefix = '/'
ancestors = list(self.get_ancestors()) + [self, ]
return prefix + '/'.join([force_text(i.slug) for i in ancestors]) + '/'
def save(self, *args, **kwargs):
super(Category, self).save(*args, **kwargs)
class Meta(CategoryBase.Meta):
verbose_name = _('category')
verbose_name_plural = _('categories')