Using Django ChoiceField gives a Value Error - python

I try to create dynamic choice. I fill choices with unit_list. Data to unit_list
loading from API (units). I set the choices dynamicly in the constructor. But when I try to save a new form, it gives 'value error'.
Have a nice day.
class Announcement(models.Model):
title = models.CharField(max_length=200, verbose_name=_('İlan Başlığı'))
unit = models.IntegerField(null=True,blank=True)
def announcement_new(request):
response = requests.get('http://127.0.0.1:8001/api/units/list/')
units = response.json()
unit_list=[]
for unit in units:
unit_list.append(((int(unit.get('id'))), str(unit.get('name'))))
ann_form = AnnouncementForm(unit_list)
if request.method == 'POST':
ann_form = AnnouncementForm( request.POST)
if ann_form.is_valid():
ann_instance = ann_form.save(commit=False)
ann_instance.save()
return redirect('ann')
else:
print('Hata: ',ann_form.errors)
else:
context = {
'ann_form':ann_form,
}
return render(request,'pages/ann/ann_new.html',context)
class AnnouncementForm(forms.ModelForm):
title = forms.CharField(widget=forms.TextInput(attrs={
"class": "form-control",
"placeholder": "",
}))
unit = forms.ChoiceField(
required=False,
widget=forms.Select(attrs={
"class": "form-control form-select select2",
}),)
def __init__(self, unit_list, *args, **kwargs):
super(AnnouncementForm, self).__init__(*args, **kwargs)
self.fields['unit'].choices = unit_list
class Meta:
model = Announcement
fields = "__all__"
Traceback (most recent call last):
File "C:\Users\feyza\OneDrive\Masaüstü\basvuru\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
response = get_response(request)
File "C:\Users\feyza\OneDrive\Masaüstü\basvuru\venv\lib\site-packages\django\core\handlers\base.py", line 204, in _get_response
self.check_response(response, callback)
File "C:\Users\feyza\OneDrive\Masaüstü\basvuru\venv\lib\site-packages\django\core\handlers\base.py", line 332, in check_response
raise ValueError(
Exception Type: ValueError at /ann/new/
Exception Value: The view apps.announcements.views.announcement_new didn't return an HttpResponse object. It returned None instead.
Hello, I found the solution by changing my method. Instead of sending the unit_list data to the form over the view, I created it directly in form.py.
class AnnouncementForm(forms.ModelForm):
title = forms.CharField(widget=forms.TextInput(attrs={
"class": "form-control",
"placeholder": "",
}))
unit = forms.ChoiceField(
required=False,
widget=forms.Select(attrs={
"class": "form-control form-select select2",
}),)
def __init__(self, *args, **kwargs):
super(AnnouncementForm, self).__init__(*args, **kwargs)
response = requests.get('http://127.0.0.1:8001/api/units/list/')
units = response.json()
unit_list=[]
for unit in units:
unit_list.append(((int(unit.get('id'))), str(unit.get('name'))))
self.fields['unit'].choices = unit_list
class Meta:
model = Announcement
fields = "__all__"

Related

Unit testing in Django for CreateView

I have a CreateView with which I create new blog posts, I want to test it in order to check if everything is ok but something is wrong with my test and I can't understand what exactly. it gives me 2 errors, for the first method I get this error:
Traceback (most recent call last):
File "C:\Users\Bularu Lilian\Desktop\EcoMon\blog\tests\test_views.py", line 73, in test_post_create_view_GET
self.assertEquals(response.status_code, 200)
AssertionError: 302 != 200
and for the second one is this error:
File "C:\Users\Bularu Lilian\Desktop\EcoMon\blog\tests\test_views.py", line 78, in test_post_create_view_POST_success
post = Post.objects.get(title=self.post['title'])
File "C:\Users\Bularu Lilian\Desktop\Environments\ecomon\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\Bularu Lilian\Desktop\Environments\ecomon\lib\site-packages\django\db\models\query.py", line 429, in get
raise self.model.DoesNotExist(
blog.models.Post.DoesNotExist: Post matching query does not exist.
This is my Test class:
class TestPostCreateViews(BaseTest):
def test_post_create_view_GET(self):
response = self.client.get(self.add_post_url)
self.assertEquals(response.status_code, 200)
self.assertTemplateUsed(response, 'blog/add_post.html')
def test_post_create_view_POST_success(self):
response = self.client.post(self.add_post_url, self.post, author=self.user, format='text/html')
post = Post.objects.get(title=self.post['title'])
self.assertEquals(response.status_code, 302)
self.assertEquals(post.title, 'test post')
my CreateView:
class PostCreateView(LoginRequiredMixin, IsSuperuserOrStaffMixin, CreateView):
template_name = 'blog/add_post.html'
form_class = PostCreateForm
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
my url path:
path('new/post/', PostCreateView.as_view(), name='add-post'),
my form:
class PostCreateForm(forms.ModelForm):
title = forms.CharField(widget=forms.TextInput(), max_length=200)
content = forms.CharField(widget=forms.Textarea(attrs={'rows': 25, 'cols': 50}))
class Meta:
model = Post
exclude = ['author', 'slug', 'published_date', 'updated_date']
and my model:
class Post(models.Model):
class PostCategory(models.TextChoices):
FAMILY = 'FAMILY', _('Family')
BUSINESS = 'BUSINESS', _('Business')
MWRKETING = 'MARKETING', _('Marketing')
SPENDINGS = 'SPENDINGS', _('Spendings')
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(_('Title'), max_length=200, unique=True)
content = models.TextField(_('Content'))
category = models.CharField(_('Category'), max_length=9, choices=PostCategory.choices, default=PostCategory.BUSINESS)
slug = models.SlugField(_('Slug'), max_length=200, blank=True, null=False, unique=True)
tags = TaggableManager(_('Tags'))
published_date = models.DateTimeField(_('Published Date/Time'), auto_now_add=True)
updated_date = models.DateTimeField(_('Updated Date/Time'), auto_now=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
#property
def comments_count(self):
return self.comments.count()
def get_absolute_url(self):
return reverse('blog')
for any help I would be greatefull
Try to write it like this:
def test_post_create_view_POST_success(self):
data = {
'author': self.user,
'title': 'test_title',
'content': 'test_content',
'category': 'test_category',
'slug': 'test_slug',
'tags': None, # or create some tags and populate
}
response = self.client.post(self.add_post_url, data=data, follow=True) # make sure your url is correct too btw that could also be the issue
self.assertEquals(response.status_code, 200)
self.assertEquals(Post.objects.filter(title='test_title').count(), 1)

Django2.1 : Queryset ModelChoice in a ModelForm then save two forms

I want the current logged in user to be able to create and save both forms. The second form has a ManyToManyField and ForeignKey relationships as you can see below.
Currently I have tried to queryset the current user from ChatGroupUser ModelForm.
With the current codes, as soon as I try to access the page, Django raise the error below:
__init__() missing 1 required positional argument: 'user'
it says that the error comes from line 88, which is:
form_user = ChatGroupUserForm()
Full Traceback
Traceback (most recent call last):
File "/Users/macadmin/Documents/Django_fun4/Groupixx/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/macadmin/Documents/Django_fun4/Groupixx/lib/python3.7/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/macadmin/Documents/Django_fun4/Groupixx/lib/python3.7/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/macadmin/Documents/Django_fun4/Groupixx/groupixx/core/views.py", line 88, in create_group
form_user = ChatGroupUserForm()
TypeError: __init__() missing 1 required positional argument: 'user'
models.py
class ChatGroup(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
group_admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='chat_group_admins')
is_active = models.BooleanField(default=True, null=True)
is_current = models.BooleanField(default=False, null=True)
class ChatGroupUser(models.Model):
user = models.ManyToManyField(User)
chat_group = models.ForeignKey(ChatGroup, on_delete=models.CASCADE, related_name='chat_group_users')
forms.py
from django.contrib.auth import get_user_model
User = get_user_model()
class ChatGroupForm(forms.ModelForm):
class Meta:
model = ChatGroup
fields = ['name',]
class ChatGroupUserForm(forms.ModelForm):
class Meta:
model = ChatGroupUser
fields = ['user']
def __init__(self, user, *args, **kwargs):
super(ChatGroupUserForm, self).__init__(*args, **kwargs)
self.fields['user'].queryset = User.objects.filter(user=user)
views.py
def create_group(request):
if request.method == 'POST':
form_group = ChatGroupForm(request.POST)
form_user = ChatGroupUserForm(request.POST)
if form_group.is_valid():
create_form = form_group.save(commit=False)
create_form.group_admin = request.user
create_form.save()
form_user.save(commit=False)
form_user.user = user
form_user.save()
return redirect('core:group_list')
else:
form_group = ChatGroupForm()
form_user = ChatGroupUserForm()
context = {
'form_group':form_group,
'form_user': form_user
}
return render(request, 'core/create-group.html', context)
I would appreciate any help, I am not sure why django is throwing an error and why i am not able to create and save both forms.
it is because your init function has parameter user,
while your view didn't pass the user.
here's how to fix it
in your view:
form_user = ChatGroupUserForm(user=request.user)
then in your form:
class ChatGroupUserForm(forms.ModelForm):
class Meta:
model = ChatGroupUser
fields = ['user']
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(ChatGroupUserForm, self).__init__(*args, **kwargs)
self.fields['user'].queryset = User.objects.filter(user=self.user)
hope it works :)

ValueError: cannot assign using Mock()

I'm learning how to use Mock for testing in django (2.0.6 <= it can make the difference) but I'm stuck following a tutorial.
Here my test_views.py:
User = get_user_model() #I use this in other tests, I hope it don't interfere
#patch('lists.views.NewListForm')
class NewListViewUnitTest(unittest.TestCase):
def setUp(self):
self.request = HttpRequest()
self.request.POST['text'] = 'new list item'
self.request.user = Mock()
def test_passes_POST_data_to_NewListForm(self, mockNewListForm):
print('self.request', self.request.user)
new_list2(self.request)
mockNewListForm.assert_called_once_with(data=self.request.POST)
[...]
And here my error on testing:
self.request <Mock name='mock()' id='80288792'> #print result
E
======================================================================
ERROR: test_passes_POST_data_to_NewListForm (lists.tests.test_views.NewListViewU
nitTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "d:\python\Lib\unittest\mock.py", line 1179, in patched
return func(*args, **keywargs)
File "D:\progetti\superlists\lists\tests\test_views.py", line 149, in test_pas
ses_POST_data_to_NewListForm
new_list2(self.request)
File "D:\progetti\superlists\lists\views.py", line 42, in new_list2
list_.owner = request.user
File "C:\Users\fabio\.virtualenvs\superlist\lib\site-packages\django\db\models
\fields\related_descriptors.py", line 197, in __set__
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "<Mock name='mock()' id='80288792'>": "List.owner" must be a "User" instance.
So, it look like it don't recognize the self.request.user = Mock() like a User instance.
Note on the test_view:
1) the print command
2) the User = get_user_model() variable. get_user_model() comes from django.contrib.auth. I think it don't interfere.
I add some more code for completeness, ask for more if you need.
My views.py:
def new_list2(request):
form = NewListForm(data=request.POST)
if form.is_valid():
list_ = List()
if request.user.is_authenticated:
list_.owner = request.user
list_.save()
form.save(owner=request.user)
return redirect(list_)
return render(request, 'home.html', {'form': form})
My forms.py:
class ItemForm(forms.models.ModelForm):
class Meta:
model = Item
fields = ('text',)
widgets = {
'text': forms.fields.TextInput(attrs={
'placeholder': 'Enter a to-do item',
'class': 'form-control input-lg',
}),
}
error_messages = {
'text': {'required': EMPTY_ITEM_ERROR}
}
def save(self, for_list):
self.instance.list = for_list
return super().save()
class NewListForm(ItemForm):
def save(self, owner):
if owner.is_authenticated:
return List.create_new(first_item_text=self.cleaned_data['text'],
owner=owner)
else:
return List.create_new(first_item_text=self.cleaned_data['text'])
My models.py:
class List(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
on_delete=models.PROTECT)
def get_absolute_url(self):
return reverse('view_list', args=[self.id])
#staticmethod
def create_new(first_item_text, owner=None):
list_ = List.objects.create(owner=owner)
Item.objects.create(text=first_item_text, list=list_)
return list_
#property
def name(self):
return self.item_set.first().text
#def __str__(self):
# return self.item_set.first().text
class Item(models.Model):
text = models.TextField(default='')
list = models.ForeignKey(List, default=None, on_delete=models.PROTECT)
class Meta:
ordering = ('id',)
unique_together = ('list', 'text')
def __str__(self):
return self.text
Please, any help will be appreciated

Apply foreign key (Brand) into the User Brand object

I am having an issue with the following line: user_brand = UserBrand(user=user, brand=serializers), I keep getting the following error:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/jeansymolanza/projects/adsoma-api/api/views.py", line 137, in post
return self.create(request, *args, **kwargs)
File "/Users/jeansymolanza/projects/adsoma-api/api/views.py", line 154, in create
user_brand = UserBrand(user=user, brand=serializers)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/models/base.py", line 439, in __init__
setattr(self, field.name, rel_obj)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py", line 207, in __set__
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "<module 'rest_framework.serializers' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/serializers.py'>": "UserBrand.brand" must be a "Brand" instance.
All I want to do is apply the foreign key (Brand) into the User Brand object.
views.py
class BrandSignup(generics.CreateAPIView):
"""
Brand signup
HTTP POST
"""
queryset = Brand.objects.all()
serializer_class = BrandSignupSerializer
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
if User.objects.filter(email=request.data['email']).exists():
response_details = {
'data': "",
'message': "This email account is already in use. Please try using another one.",
'code': "400",
'status': HTTP_400_BAD_REQUEST
}
return Response(response_details, status=response_details['status'])
else:
serializer = self.get_serializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
user = User(email=request.data['email'], password=request.data['password'],
account_type=request.data['account_type'])
user.save()
user_brand = UserBrand(user=user, brand=serializer)
user_brand.save()
response_details = {
'data': request.data,
'message': "Account created successfully.",
'code': "201",
'status': HTTP_201_CREATED
}
else:
response_details = {
'data': serializer.errors,
'message': "Your account cannot be created at this moment in time. Please try again later.",
'code': "400",
'status': HTTP_400_BAD_REQUEST
}
return Response(response_details, status=response_details['status'])
models.py
class Brand(models.Model):
"""
Brand model
"""
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255, null=True, default=None)
brand = models.CharField(max_length=255, null=True, default=None)
phone = models.CharField(max_length=255, null=True, default=None)
website = models.CharField(max_length=255, null=True, default=None)
class Meta:
verbose_name_plural = "Brands"
def __str__(self):
return "%s" % self.brand
class UserBrand(models.Model):
"""
User brand model
"""
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
user = models.ForeignKey(User, null=False, on_delete=models.CASCADE)
brand = models.ForeignKey(Brand, null=False, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "User Brands"
def __str__(self):
return "%s - %s" % (self.user, self.brand)
You're trying to pass a BrandSignupSerializer object to the UserBrand constructor as the brand... You need a Brand object instead. You should be able to fix this by replacing your line with
user_brand = UserBrand(user=user, brand=serializer.instance)

Django REST framework serializer error when instantiating

I'm having an strange issue with DRF ans some serializers.
Here is my model:
class Accommodation(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
product = models.OneToOneField(
Product,
on_delete=models.CASCADE,
primary_key=True,
)
description = models.TextField(null=True, blank=True, verbose_name=_(u'Description'))
shared_accommodation = models.BooleanField(default=False)
accommodation_unit_quantity = models.PositiveSmallIntegerField(default=1,
verbose_name=_(u'Number of acommodation units '
u'for this acommodation'))
accommodation_unit_name = models.TextField(null=False, blank=False, verbose_name=_(u'Name for accommodation units '
u'for this accommodation'))
class Meta:
verbose_name_plural = _(u'Accommodations')
def __unicode__(self):
return u'{0} <{1}>'.format(self.product.name, self.product.school)
class Product(AbstractProduct):
name = models.CharField(max_length=50, verbose_name=_(u'Name'))
school = models.ForeignKey('school.School')
levels = models.ManyToManyField('school.Level',verbose_name=_(u'Level'))
age = IntegerRangeField(null=True)
gender = models.CharField(choices=GENDER_CHOICES, max_length=1, null=True, blank=True, verbose_name=_(u'Gender'))
num_sessions = models.PositiveSmallIntegerField(
verbose_name=_(u'Number of sessions'),
default=1,
help_text=_(u"Number of sessions that the product has."),
)
school_category = models.ForeignKey(
'school.Category',
blank=True, null=True,
verbose_name=_(u'Category')
)
addons = models.ManyToManyField('self',
verbose_name=_(u'Administrators'),
through='AddonInService',
symmetrical=False,
related_name='addon_can_be_used_in'
)
pay_option = models.CharField(choices=PAYMENT_OPTIONS, max_length=1, null=True, blank=True, verbose_name=_(u'Pay_option'), default='U')
payment_type = models.CharField(choices=PAYMENT_TYPE, max_length=1, null=True, blank=True, verbose_name=_(u'pay_type'))
payment_amount = models.FloatField(verbose_name=_(u'Amount'), default=0.0)
objects = ProductManager()
class Meta(AbstractProduct.Meta):
verbose_name_plural = _(u'Products')
def __unicode__(self):
return self.name
As you can see, basically a Product can be an Accommodation. Here are the Serializers
class AccommodationSerializer(serializers.ModelSerializer):
class Meta:
model = Accommodation
fields = [
'description',
'shared_accommodation',
'accommodation_unit_quantity',
'accommodation_unit_name',
]
class ProductAccommodationSerializer(ProductSerializer):
accommodation = AccommodationSerializer()
class Meta(ProductSerializer.Meta):
fields = [
'id',
'structure',
'upc',
'title',
'slug',
'description',
'rating',
'date_created',
'date_updated',
'is_discountable',
'name',
'age',
'gender',
'num_sessions',
'parent',
'product_class',
'school',
'levels',
'school_category',
'addons',
'color',
'price',
'all_prices',
'variants',
'pay_option',
'payment_type',
'payment_amount',
'accommodation',
]
def create(self, validated_data):
accommodation_data = validated_data.pop('accommodation')
levels = []
if 'levels' in validated_data:
levels = validated_data.pop('levels')
product = Product.objects.create(**validated_data)
school_accommodation, created = ProductClass.objects.get_or_create(name='School Accommodation')
if created:
product.product_class = school_accommodation
for lev in levels:
product.levels.add(lev)
product.save()
acc = AccommodationSerializer(product=product, **accommodation_data)
acc.save()
return product
class ProductSerializer(serializers.ModelSerializer):
age = IntegerRangeField()
addons = AddonSerializer(many=True, read_only=True)
# Get the price for the Product, using the property in the Model
price = serializers.DecimalField(required=False, max_digits=7,
decimal_places=2, source='get_price',
read_only=True)
color = serializers.SerializerMethodField()
all_prices = PriceSerializer(source='stockrecords', many=True,
required=False)
variants = VariantSerializer(many=True, source='children', required=False)
class Meta:
model = Product
fields = [
'id',
'structure',
'upc',
'title',
'slug',
'description',
'rating',
'date_created',
'date_updated',
'is_discountable',
'name',
'age',
'gender',
'num_sessions',
'parent',
'product_class',
'school',
'levels',
'school_category',
'addons',
'color',
'price',
'all_prices',
'variants',
'pay_option',
'payment_type',
'payment_amount'
]
Performing a simple test where I try to create an Accommodation, I get the following error:
Traceback (most recent call last):
File "/home/internetmosquito/git/mvp_opencoast/opencoast_django/opencoast/applications/accommodation/tests/test_accommodations.py", line 165, in test_create_accommodation
response = self.client.post(url, data, format='json')
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 170, in post
path, data=data, format=format, content_type=content_type, **extra)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 92, in post
return self.generic('POST', path, data, content_type, **extra)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/test/client.py", line 380, in generic
return self.request(**r)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 159, in request
return super(APIClient, self).request(**kwargs)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 111, in request
request = super(APIRequestFactory, self).request(**kwargs)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/test/client.py", line 467, in request
six.reraise(*exc_info)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/viewsets.py", line 87, in view
return self.dispatch(request, *args, **kwargs)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 21, in create
self.perform_create(serializer)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 26, in perform_create
serializer.save()
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 191, in save
self.instance = self.create(validated_data)
File "/home/internetmosquito/git/mvp_opencoast/opencoast_django/opencoast/applications/accommodation/serializers.py", line 77, in create
acc = AccommodationSerializer(product=product, **accommodation_data)
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 95, in __init__
super(BaseSerializer, self).__init__(**kwargs)
TypeError: __init__() got an unexpected keyword argument 'product'
Tried to remove the
product=product
From
acc = AccommodationSerializer(product=product, **accommodation_data)
But then I get the same error but with 'shared_accommodation' field instead of product
WHat I'm doing wrong here? Any ideas?
EDIT: Added ProductSerializer, I missed that one sorry
SECOND EDIT: As suggested by some, I've added the product field to the AccommodationSerializer:
class AccommodationSerializer(serializers.ModelSerializer):
class Meta:
model = Accommodation
fields = [
'product',
'description',
'shared_accommodation',
'accommodation_unit_quantity',
'accommodation_unit_name',
]
But then when trying to create an instance, I get the following error:
{'accommodation': OrderedDict([('product', [u'This field is required.'])])}
Funny enough, if I add the product to the test data payload (even though I haven't created the product at the time I call the endpoint to make an Accommodation, the error above dissappears):
data = {
"name": "Hotel Hudson",
"slug": "hotel-hudson",
"age": {'upper': 99, 'lower': 18},
"school": school1.id,
"levels": [school1.level_set.all()[0].id],
"accommodation": {
"product": 1,
"description": "A very nice hotel",
"shared_accommodation": False,
"accommodation_unit_quantity": 1,
"accommodation_unit_name": "Room",
"accommodation_units": [
{
'name': "Room-1",
'max_pax': 1,
},
{
'name': "Room-2",
'max_pax': 3,
},
]
},
}
While this is interesting, this is obviously not what I want...I don't want having to pass a fake product ID when calling the endpoint to create an Accommodation...any pointers?
Using the data field would be the right way since the keywords in the DRF Serializer hierarchy are not generic. If the dictionary you specifiy for data is valid you could create a model instance with .save() (after calling .is_valid()). The dictionary could of course be augmented with further attributes before creating the model. But beware, that the serializer only uses the attributes, which are specied in the Meta.fields field of the serializer.
And here is the critical point, why your approach would not work after all: the AccomodationSerializer.Meta.fields does not include the product field, which is mandatory if you want to create a model.
It is fine to use AccommodationSerializer to read from the Accommodation model or if you want to post a partial structure of the model for some reason. But if you want to use it to create a model instance, you have to specify all fields which are not nullable or have a default value.
Instead of using the AccommodationSerializer here, you could just call:
Accommodation.objects.create(product=product, **accommodation_data)
I tried to set up a minimal example. Hope this helps.
models.py:
class Owner(models.Model):
owner_name = models.CharField(max_length=255)
class Product(models.Model):
name = models.CharField(max_length=255)
owner = models.OneToOneField(Owner)
serializer.py
class OwnerSerializer(serializers.ModelSerializer):
class Meta:
model = Owner
fields = [
'owner_name',
]
class ProductSerializer(serializers.ModelSerializer):
owner = OwnerSerializer(read_only=True)
class Meta:
model = Product
fields = [
'owner',
'name',
]
class ProductOwnerSerializer(serializers.ModelSerializer):
product = ProductSerializer()
class Meta:
model = Owner
fields = [
'product',
'owner_name',
]
def create(self, validated_data):
product_data = validated_data.pop('product')
owner = Owner.objects.create(**validated_data)
Product.objects.create(owner=owner, **product_data)
return owner
I also agree with Jerzyk's comment, that I really don't like the Meta(Superclass), seems like an anti-pattern to me.

Categories

Resources