Django rest framework create object with many-to-many filed serializer - python-3.x

I can't create a project object with many-to-many field to languages model. I need to find the best way to implement this. I have tried the django rest framework docs, but it didn't work for me. Do the language objects need to be created before the project object or DRF will handle this? This problem occurs when I added the owner field, then I needed to add the create method inside the ProjectSerializer to save the object owner, but then this error occurred: Direct assignment to the forward side of a many-to-many set is prohibited. Use languages.set() instead.
I tried languages.set() but it still does not work.
models.py
from django.db import models
from django.contrib.auth.models import User
class Language(models.Model):
name = models.CharField(max_length=100, blank=True, default='')
description = models.TextField()
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['id']
def __str__(self):
return self.name
class Developer(models.Model):
name = models.CharField(max_length=100, blank=True, default='')
age = models.IntegerField()
bio = models.TextField()
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['created']
def __str__(self):
return self.name
class Project(models.Model):
name = models.CharField(max_length=100, blank=True, default='')
stars = models.IntegerField()
developer = models.ForeignKey(Developer, related_name='projects', on_delete=models.CASCADE)
languages = models.ManyToManyField(Language)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['stars']
def __str__(self):
return self.name
serializers.py
from rest_framework import serializers
from developers.models import Language, Developer, Project
class ProjectSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Project
fields = ['id', 'name', 'stars', 'developer', 'languages', 'owner', ]
def create(self, validated_data):
project = Project.objects.create(owner=self.context['request'].user, **validated_data)
return project
class LanguageSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
projects = ProjectSerializer(read_only=True, many=True)
class Meta:
model = Language
fields = ['id', 'name', 'description', 'projects', 'owner', ]
def create(self, validated_data):
language = Language.objects.create(owner=self.context['request'].user, **validated_data)
return language
class DeveloperSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
projects = ProjectSerializer(read_only=True, many=True)
class Meta:
model = Developer
fields = ['id', 'name', 'age', 'bio', 'projects', 'owner', ]
def create(self, validated_data):
developer = Developer.objects.create(owner=self.context['request'].user, **validated_data)
return developer

Related

Error: (admin.E035) The value of 'readonly_fields[0]' is not a callable

Summarize the problem
<class 'news.admin.NewsAdmin'>: (admin.E035) The value of 'readonly_fields[0]' is not a callable, an attribut
e of 'NewsAdmin', or an attribute of 'news.News'.
This all code error. I learn Django, and write code how in author. But write this error :(
Describe what you`ve tried
I immediately insert problem in search, but not found decision
I read this question, but it not finished
This question elementary, author question not correct write variable
Show some code
admin.py
from django.contrib import admin
from .models import News, Category
class NewsAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'category', 'create_at', 'updated_at', 'is_published')
list_display_links = ('id', 'title',) # what be links in model
search_fields = ('title', 'content',)
list_editable = ('is_published',) # redact is published in menu
list_filter = ('is_published', 'category',) # create table, what in be setting sorted
fields = ('title', 'category', 'content', 'photo', 'get_photo', 'is_published', 'views',
'create_at', 'updated_at')
readonly_fields = ('get_photo', 'views', 'create_at', 'updated_at')
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'title') # displays
list_display_links = ('id', 'title') # links
search_fields = ('title',)
admin.site.register(News, NewsAdmin)
admin.site.register(Category, CategoryAdmin)
models.py
from django.db import models
from django.urls import reverse
class News(models.Model):
title = models.CharField(max_length=150)
content = models.TextField(blank=True)
create_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
is_published = models.BooleanField(default=True)
category = models.ForeignKey('Category', on_delete=models.PROTECT)
views = models.IntegerField(default=0)
def get_absolute_url(self):
return reverse('view_news', kwargs={"news_id": self.pk})
def __str__(self): # return number position model
return self.title
objects = models.Manager()
class Meta:
verbose_name = 'NEWS'
verbose_name_plural = 'NEWS'
ordering = ['-create_at']
class Category(models.Model):
title = models.CharField(max_length=150, db_index=True, verbose_name='Title category')
def get_absolute_url(self):
return reverse('category', kwargs={"category_id": self.pk})
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
ordering = ['title']
def __str__(self): # String views. If not be this parameters, be number vice world
return self.title
Since you've put 'get_photo' in NewsAdmin.read_only_fields and it is not a model field, it's supposed to be a method or a property in either News or NewsAdmin.
You should change it to 'photo' because read_only_fields only meant for fields to be non-editable.
class NewsAdmin(admin.ModelAdmin):
...
readonly_fields = ('photo', 'views', 'create_at', 'updated_at')
Try to add 'views' to list_display.
Probably a field can't be in read_only_fields unless it's shown in list_display.

django UpdateView get_success_url not returning to profile page

I am still new to django and have encountered this issue, the situation is like this, I have a profile model, on which I have 2 views ViewProfile and EditProfile inheriting from DetailView and UpdateView respectively. when I edit the profile page, it doesn't get me to the profile page instead it gave the error:
Reverse for 'profile' with keyword arguments '{'id': 9}' not found. 1 pattern(s) tried: ['profile/(?P<pk>[^/]+)/\\Z']
even though I have checked in the python shell, the profile with id:9 is indeed profile with name muham see below
>>> Profile.objects.all()
<QuerySet [<Profile: huzaifa>, <Profile: another1>, <Profile: muham>]>
>>> p1 = Profile.objects.get(name='muham')
>>> p1.id
9
>>>
but still its not showing,
I have overridden the get_success_url to get me to the profile page:
class EditProfile(LoginRequiredMixin, UpdateView):
model = Profile
fields = ('name', 'address', 'phone_no',)
template_name = 'blog_app/edit_profile.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user'] = self.request.user
return context
def get_success_url(self):
id = self.request.user.profile.id
return reverse_lazy('profile', kwargs={'id': id})
my model is below:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=60, blank=True, null=True)
address = models.CharField(max_length=400, null=True, blank=True)
# image
phone_no = models.CharField(max_length=40, null=True, blank=True)
def __str__(self):
return str(self.user)
class ViewProfile(LoginRequiredMixin, DetailView):
model = Profile
template_name = 'blog_app/profile.html'
context_object_name = 'profile'
urls.py:
urlpatterns = [
path('', ListBlog.as_view(), name='home'),
path('my-blogs/', MyBlog.as_view(), name='my-blogs'),
path('create-blog/', CreateBlog.as_view(), name='blog-create'),
path('blog-detail/<int:pk>/', BlogDetail.as_view(), name='blog-detail'),
path('edit-blog/<int:pk>/', EditBlog.as_view(), name='blog-edit'),
path('delete-blog/<int:pk>/', DeleteBlog.as_view(), name='blog-delete'),
path('profile/<str:pk>/', ViewProfile.as_view(), name='profile'),
path('edit-profile/<str:pk>/', EditProfile.as_view(), name='edit-profile'),
]
I have found my error, it was because DetailView uses pk or slug, on the urlconf arguments, and before i have added str:id instead of str:pk, and also in the
def get_success_url(self):
id = self.request.user.profile.id
return reverse_lazy('profile', kwargs={'id': id})
i had kwargs={'id':id} instead of {"pk": id}. so that was my issue, and it was resolved after that.

Django Rest Framework not saving all foreign key objects

I am going to create a conference and select multiple departments, it is working when I send post request but in GET resquest not getting objects.
class DepartmentModel(models.Model):
name = models.CharField(max_length=255)
conference = models.ForeignKey('ConferenceModel', on_delete=models.CASCADE, null=True,
related_name='conference_departments')
class ConferenceModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
description = models.CharField(max_length=255, null=True)
serializers.py
class DepartmentField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
pk = super(DepartmentField, self).to_representation(value)
try:
item = DepartmentModel.objects.get(pk=pk)
serializer = DepartmentSerializer(item)
return serializer.data
except DepartmentModel.DoesNotExist:
return None
def get_choices(self, cutoff=None):
queryset = self.get_queryset()
if queryset is None:
return {}
return OrderedDict([(item.id, str(item)) for item in queryset])
class ConferenceModelSerializer(serializers.ModelSerializer):
conference_departments = DepartmentField(queryset=DepartmentModel.objects.all(), many=True)
meeting_participants = SelectItemField(model='account.User', extra_field=['first_name', 'last_name'], many=True)
class Meta:
model = ConferenceModel
fields = '__all__'
request
{
"conference_departments": [
3, 4, 5, 7, 8
],
"meeting_participants": [
10, 12, 15
],
"description": "Bla bla bla"
}
it returns the expected result but If I want to save another object and get all objects it does not return objects but the latest one does.
here you can see from the image below
id: 19 is the latest saved object it returns department objects but id: 18 does not!
can anybody help me please? any help would be appreciated! Thanks in advance!
class DepartmentSerializer(serializers.ModelSerializer):
...
class Meta:
model = DepartmentModel
fields = '__all__'
class ConferenceModelSerializer(serializers.ModelSerializer):
conference_departments = DepartmentSerializer(required=False, many=True)
meeting_participants = SelectItemField(model='account.User', extra_field=['first_name', 'last_name'], many=True)
class Meta:
model = ConferenceModel
fields = '__all__'
Nested relationships
Writable nested serializers

How to join two tables in django and serialize the same using one serializer?

I have been learning django and django rest framework since couple of weeks and I want to figure out how can I join two tables and serialize the data of same to return the json response using django rest framework.
I want to return result as json response:
{ 'user_id_id': 1, 'request_msg': 'Hi', 'response_msg': "Hi, Welcome" }
where result is
from django.db import connection
cursor = connection.cursor()
con = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
Here is what I have tried :
#backend/Models.py
class User(models.Model):
username = models.CharField(max_length=50)
name = models.CharField(max_length=50, blank=True, null=True)
uid = models.CharField(max_length=12, blank=True, null=True)
age = models.CharField(max_length=3, blank=True, null=True)
active = models.BooleanField(default=True)
class Meta:
default_related_name = 'users'
def __str__(self):
return self.name
class Request_Messages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class Response_Messages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'response_messages'
def __str__(self):
return self.response_msg
#backend/serializers.py
class ListSerializer (serializers.Serializer):
user_id_id = serializers.IntegerField()
request_msg = serializers.CharField(max_length=100)
# request_msg_created_at = serializers.DateTimeField(read_only=True)
response_msg = serializers.CharField()
# response_msg_created_at = serializers.DateTimeField(read_only=True)
#backend/views.py
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Response_Messages, Request_Messages, User
from .serializers import ListSerializer
from django.db import connection
#api_view(['GET', 'POST'])
def chatbot(request):
if request.method == 'GET':
cursor = connection.cursor()
query_set = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
columns = [column[0] for column in query_set.description]
results = []
for row in query_set.fetchall():
results.append(dict(zip(columns, row)))
serializer = ListSerializer(results)
return Response(serializer.data)
About serializers, You should refer to the docs (they're awesome and explain it best).
To give you a direction, I like to create a serializer for every model and if it's related to another model, I refer that in serializer, that way, You can easily customize behavior for each model (although not the only way at all).
So, about serializing I would do the following (notice my comments as well):
from django.contrib.auth.models import User
class User(User):
# Your user class, except, it should inherit Django's User/AbstractUser class.
class RequestMessages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
User, on_delete=models.CASCADE, null=True, related_name='requests_msg')
# NOTICE THE NEW RELATED NAME, WE'LL USE IT LATER.
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class ResponseMessages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='responses_msg')
def __str__(self):
return self.response_msg
class RequestMsgSerializer(serializers.ModelSerializer):
# Specify what ever you like...
class Meta:
model = RequestMessages
fields = # Whatever you like to serialize.
class ResponseMsgSerializer(serializers.ModelSerializer):
class Meta:
model = ResponseMessages
fields = # Whatever you want serialized.
class UserSerializer(serializers.ModelSerializer):
# Using required = False will cause that every time you create a user they don't have to own messages.
requests_msg = RequestMsgSerializer(many=False, required=False)
responses_msg = ResponseMsgSerializer(many=False, required=False)
class Meta:
model = User
field = # Same as above ..
About your query, using raw SQL in Django is rear, usually, in most cases the Django built-in ORM will do the job and usually faster and better than you.
In your case, if you'll call your query like this for exmaple:
query_set = User.objects.filter(user=request.user)
the QuerySet object created will hit the DB one for the user object and X queries for all the associated messages with said user, so expensive.
But no need for a custom query with joins and stuff like that, Django has prefetch_related and select_related.
exmaple:
query_set = User.objects.filter(user=request.user).prefetch_related('requests_msg')
will reduce all the queries made for request messages associated to a user to only one!
Recap:
I wrote a lot because I'm still learning this stuff myself self and if you teach others you got it!
Refer to DRF's docs about serializers (there's even a dedicated section for nested serializers) and API Views, they really great.
Refer to Django's docs about prefetch related, select related and queries in general, again, Amazing docs that cover everything.
Don't just copy my code or anyone else's, there's no problem with that, just make sure you understand it first if not, you're bound to get stuck with it again!

Adding comment feature in Django DetailView?

What the simplest logic i can add in class HotelDetailView(DetailView) so users can comment on a particular hotel detail page. And it capture user too.
models.py
class Hotel(models.Model):
name = models.CharField(max_length=150)
owner = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
image = models.ImageField(upload_to=upload_location, null=True, blank=True)
class CommentOnHotel(models.Model):
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField(max_length=200)
published = models.DateField(auto_now_add=True)
def __str__(self):
return '{} - {}'.format(self.hotel.name, self.user.email)
Forms.py
class CommentOnHotelForm(forms.ModelForm):
class Meta:
model = CommentOnHotel
fields = ['content']
views.py
class HotelDetailView(DetailView):
model = Hotel
........
actually i gave you the better approach for that, but if you want to make all logic and functions at DetailView which is not recommended, here is the solution, you need to override POST function of DetaiView:
class HotelDetailView(DetailView):
model = Hotel
def post(self, request, *args, **kwargs):
# get the hotel object
hotel = self.get_object()
#check for validation of form
form = CommentOnHotelForm({
"hotel": hotel,
"user" :request.user
"comment": request.POST.comment
})
if form.is_valid():
form.save()
#choose where you want to redirect

Resources