Related Field got invalid lookup: blog_posts_name - python

I am trying to add author to the search_field but it's throwing the error-Related Field got invalid lookup: icontains
models.py
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,unique_for_date='publish')
author = models.ForeignKey(User,
on_delete=models.CASCADE,related_name='blog_posts')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='draft')
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
admin.py
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'publish',
'status')
list_filter = ('status', 'created', 'publish', 'author')
search_fields = ('title', 'body','status','author__blog_posts_name')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'publish'
ordering = ('status', 'publish')
I have tried search_fields =('author','foreinkeyfield__author','author__name','author__User_name',)
as per suggested by the users in the previously answered questions but none of them seems to be working.

Django's User model has the following fields (and others that are probably not relevant for searching by name):
username
first_name
last_name
email
You can only use existing fields in the lookups while the fields you have listed do not reference any valid DB fields.
The lookups for the above fields would look like this:
search_fields = (
'author__username',
'author__first_name',
'author__last_name',
'author__email',
)

Related

DRF Add annotated field to nested serializer

I have two serializers that represent comments and their nested comments. I'm provide a queryset to viewset with annotated field likes. But my problem is that field only working in parent serializer. When i add this field to nested serializer i got error
Got AttributeError when attempting to get a value for field likes on serializer CommentChildrenSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Comment instance.
Original exception text was: 'Comment' object has no attribute 'likes'.
Here is some my code. Thanks
Models.py
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
slug = models.SlugField(blank=True)
body = models.TextField()
tags = TaggableManager(blank=True)
pub_date = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-pub_date']
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE,
related_name='comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
text = models.TextField(max_length=500)
pub_date = models.DateTimeField(auto_now=True)
parent = models.ForeignKey('self', blank=True, null=True,
on_delete=models.CASCADE, related_name='children')
class Meta:
ordering = ['-pub_date']
class Vote(models.Model):
comment = models.ForeignKey(Comment, on_delete=models.CASCADE,
related_name='votes')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
choice = models.BooleanField(null=True)
Serializers.py
class PostRetrieveSerializer(PostSerializer):
comments = CommentSerializer(read_only=True, many=True)
author = AuthorInfoSerializer(serializers.ModelSerializer)
class Meta:
model = Post
fields = ['id', 'author', 'slug', 'title', 'body', 'tags', 'pub_date', 'comments']
class CommentChildrenSerializer(serializers.ModelSerializer):
author = AuthorInfoSerializer(read_only=True)
likes = serializers.IntegerField()
class Meta:
model = Comment
fields = ['author', 'id', 'text', 'pub_date', 'parent', 'likes']
class CommentSerializer(serializers.ModelSerializer):
author = AuthorInfoSerializer(read_only=True)
children = CommentChildrenSerializer(many=True)
likes = serializers.IntegerField()
class Meta:
ordering = ['pub_date']
model = Comment
fields = ['author', 'id', 'text', 'pub_date', 'children', 'likes']
Views.py
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all().prefetch_related(
Prefetch('comments', queryset=Comment.objects.filter(parent__isnull=True)
.annotate(likes=Count('votes__choice'))))
serializer_class = PostSerializer
permission_classes = [IsOwnerOrAdminOrReadOnly]
pagination_class = PostPagination
lookup_field = 'slug'
def get_serializer_class(self):
""""
Attach related comments
when get post detail
"""
if self.action == 'retrieve':
return PostRetrieveSerializer
return self.serializer_class
def perform_create(self, serializer):
serializer.save(author=self.request.user)
maybe you can do something like this, adding the like field in each child comment.
queryset = Post.objects.all()\
.prefetch_related(
Prefetch(
'comments',
queryset=Comment.objects\
.filter(parent__isnull=True)\
.annotate(likes=Count('votes__choice'))\
.prefetch_related(
'children',
queryset=Comments.objects.all()\
.annotate(likes=Count('votes__choice'))
)
)
)
I hope this help you.
Regards!
On your model level, add a custom property like the below.
class Comment(models.Model):
...
class Meta:
ordering = ['-pub_date']
#property
def likes(self):
return self.votes.count()
On your serializer add SerializerMethodField
class CommentChildrenSerializer(serializers.ModelSerializer):
author = AuthorInfoSerializer(read_only=True)
likes = serializers.SerializerMethodField() # Change here
class Meta:
model = Comment
fields = ['author', 'id', 'text', 'pub_date', 'parent', 'likes']
# method for the SerializerMethodField
def get_likes(self, obj):
return obj.likes
Update both Comment related serializers. I believe this approach is simpler than the current implementation.

Creating view with foreign key model django restframework

I'm fairly new with the django restframework.
I am trying to create a serializer and a view for a model that has a foreignKey.
Models.py
class Job(models.Model):
"""A Job used to create a job posting"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
description = models.TextField()
job_type = models.CharField(max_length=12, choices=JOB_TYPE_CHOICES, default='Full-Time')
city = models.CharField(max_length=255)
state = models.CharField(max_length=255)
created_date = models.DateField(auto_now=False, auto_now_add=True)
salary = models.CharField(max_length=255)
position = models.CharField(max_length=255)
employer = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.description[:50]
class Applicant(models.Model):
"""A applicant that can apply to a job"""
job = models.ForeignKey(Job, on_delete=models.CASCADE)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(max_length=254)
phone_number = PhoneNumberField()
resume = models.FileField(upload_to=resume_file_path, validators=[validate_file_extension])
def __str__(self):
return self.first_name
The idea is that Applicant will be able to apply to Job.
I can't seem to figure out how to get the Job id when a Applicant is applying to job.
serializers.py
class JobSerializer(serializers.ModelSerializer):
"""Serializer for tag objects"""
class Meta:
model = Job
fields = ('id', 'description', 'job_type', 'city', 'state', 'salary', 'position', 'employer', 'created_date', 'is_active')
read_only_fields = ('id',)
def create(self, validated_data):
"""Create a job posting with user and return it"""
return Job.objects.create(**validated_data)
class ApplyJobSerializer(serializers.ModelSerializer):
"""Serializer for applying to jobs"""
class Meta:
model = Applicant
fields = ('id', 'first_name', 'last_name', 'email', 'phone_number', 'resume')
read_only_fields = ('id',)
views.py
class ApplyJobView(generics.CreateAPIView):
"""Allows applicants to apply for jobs"""
serializer_class = serializers.ApplyJobSerializer
Below is an image of my http://localhost:8000/api/jobPosting/apply/ url
I don't know how i can bring in the Jobs as in option to my view so I can obtain the id field.
I get the following error when POST
null value in column "job_id" violates not-null constraint
You are not passing job field in serializer fields. Try this:
class ApplyJobSerializer(serializers.ModelSerializer):
"""Serializer for applying to jobs"""
class Meta:
model = Applicant
fields = ('id', 'first_name', 'last_name', 'email', 'phone_number', 'resume', 'job')
read_only_fields = ('id',)

Django call 'id' expected a number but got string

Django errors with django-import-export libraries.
I want to import data from excel to db via django admin. I use for it django-import-export, but i got Field 'id' expected a number but got 'HPI'.
Excel file contains
I found answer, that I have to add exclude = ('id',), but it didn't help. Also i did migrations, it didn't help too.
How to fix it and have ability to import 6 columns data from excel to db via django admin?
models.py
from django_mysql.models import JSONField, Model
from django.db import models
class Category(Model):
title = models.CharField(max_length=100)
class Meta:
ordering = ('-id',)
verbose_name = 'Category'
verbose_name_plural = 'Categories'
def __str__(self):
return self.title
class Tag(Model):
title = models.CharField(max_length=100)
class Meta:
ordering = ('-id',)
def __str__(self):
return self.title
class Type(Model):
title = models.CharField(max_length=100)
class Meta:
ordering = ('-id',)
verbose_name = 'Type'
verbose_name_plural = 'Types'
def __str__(self):
return self.title
class Macro(Model):
type = models.ForeignKey(
Type,
max_length=100,
null=True,
blank=True,
on_delete=models.SET_NULL)
tags = models.ManyToManyField(Tag, blank=True)
category = models.ForeignKey(
Category, null=True, blank=True, on_delete=models.SET_NULL)
abbreviation = models.CharField(max_length=100, unique=True)
title = models.CharField(max_length=100, verbose_name='Title')
content = models.TextField(max_length=1000, null=True, blank=True)
class Meta:
ordering = ('-id',)
def __str__(self):
return self.title
admin.py
from django.contrib import admin
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from .models import Category, Tag, Type, Macro
class MacroResource(resources.ModelResource):
class Meta:
model = Macro
skip_unchanged = True
report_skipped = True
exclude = ('id', )
export_order = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')
#admin.register(Macro)
class MacroAdmin(ImportExportModelAdmin):
resource_class = MacroResource
list_display = ('id', 'type', 'tags_list', 'category', 'abbreviation', 'title', 'content')
search_fields = ('title', 'category__title', 'type__title', 'abbreviation', 'content', )
def tags_list(self, obj):
tags = [t for t in obj.tags.all()]
return ' '.join(str(tags)) if tags else '-'
#admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'title')
#admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ('id', 'title')
def __str__(self):
return self.title
#admin.register(Type)
class TypeAdmin(admin.ModelAdmin):
list_display = ('id', 'title')
The problem was with ForeignKey and ManyToMany fields of a database model. So django-import-export library need to get widgets for this fields.
More about it here: https://django-import-export.readthedocs.io/en/latest/api_widgets.html#import_export.widgets.ForeignKeyWidget
Solution:
admin.py
class MacroResource(resources.ModelResource):
type = fields.Field(
column_name='type',
attribute='type',
widget=ForeignKeyWidget(Type, 'title'))
category = fields.Field(
column_name='category',
attribute='category',
widget=ForeignKeyWidget(Category, 'title'))
tags = fields.Field(
column_name='tags',
attribute='tags',
widget=ManyToManyWidget(Tag, field='title'))
class Meta:
model = Macro
skip_unchanged = True
report_skipped = True
exclude = ('id', )
import_id_fields = ('title',)
fields = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')
instead of
class MacroResource(resources.ModelResource):
class Meta:
model = Macro
skip_unchanged = True
report_skipped = True
exclude = ('id', )
export_order = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')
Django-import-export expects the first column to be id.
If these are new objects, simply leave the id column blank. Otherwise, put the database id of the object in that field.
If you're not able to modify the file, or don't want to, and you will always be adding new rows to the database (not modifying existing ones), you can create an id field dynamically in your resource class by overriding the method before_import and forcing get_instance to always return False.
class MacroResource(resources.ModelResource):
def before_import(self, dataset, using_transactions, dry_run, **kwargs):
dataset.insert_col(0, col=["",]*dataset.height, header="id")
def get_instance(self, instance_loader, row):
return False
class Meta:
model = Macro
skip_unchanged = True
report_skipped = True
export_order = ('type', 'tags', 'category', 'abbreviation', 'title', 'content')
The attributes where you are using a foreign key in the model,
you need to specify the id of the parent model and not the value in the xlsx/csv file.

Django REST Framework ModelSerializer read_only_fields not working

I have the following ListCreateAPIView
class TodoAPI(generics.ListCreateAPIView):
permission_classes = (IsAuthenticated, )
serializer_class = TodoSerializer
def get_queryset(self):
user = self.request.user
return Todo.objects.filter(user=user)
And in my serializers.py, I have
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = ('id', 'title', 'description',
'completed', 'created_at')
read_only_fields = ('id', )
But the problem is when I POST data into the form, I get the following error:
IntegrityError at /todo/
NOT NULL constraint failed: todo_todo.user_id
models.py
class Todo(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.TextField(max_length=50)
description = models.TextField(max_length=200, blank=True, null=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
The problem is not with id field, but with user field. This field is not nullable in DB and since is required. You can just pass current user as defalt, for this use CurrentUserDefault:
class TodoSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Todo
fields = ('id', 'title', 'description',
'completed', 'created_at', 'user')

django rest framework nested relationships -

I have some trouble understanding Django Rest Framework. I am building an application, very simple. And for some reason I don't understand I am not able to make it work properly.
I am using:
python: 3.4.0
Django: 1.7.4
Django Rest Framework: 3.0.5
Here is the thing:
#models.py
class Country(StandardMetadata, GeoBase):
CONTINENT_CHOICES = (
('OC', 'Oceania'),
('EU', 'Europe'),
('AF', 'Africa'),
('NA', 'North America'),
('AN', 'Antarctica'),
('SA', 'South America'),
('AS', 'Asia'),
)
name = models.CharField(max_length=200, db_index=True)
slug = AutoSlugField(populate_from='name')
continent = models.CharField(max_length=2, choices=CONTINENT_CHOICES, default='NA')
iso2 = models.CharField(max_length=2)
iso3 = models.CharField(max_length=3)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Countries'
class Region(StandardMetadata, GeoBase):
name = models.CharField(max_length=200, db_index=True)
slug = AutoSlugField(populate_from='name')
iso2 = models.CharField(max_length=2)
country = models.ForeignKey(Country)
def __str__(self):
return self.get_full_name()
def get_full_name(self):
return ', '.join([self.name, self.country.name])
class Meta:
unique_together = ('slug', 'country')
verbose_name = 'Region/State/Province'
verbose_name_plural = 'Regions/States/Provinces'
#serializers.py
class CountrySerializer(serializers.ModelSerializer):
class Meta:
model = Country
fields = ('id', 'name', 'slug', 'iso2', 'iso3', 'continent', 'lng', 'lat')
class RegionSerializer(serializers.ModelSerializer):
country = CountrySerializer(read_only=True, required=True, many=False)
class Meta:
model = Region
fields = ('id', 'name', 'slug', 'iso2', 'lng', 'lat', 'country',)
#views.py
class CountryViewSet(viewsets.ModelViewSet):
queryset = Country.objects.all()
serializer_class = CountrySerializer
class RegionViewSet(viewsets.ModelViewSet):
queryset = Region.objects.all()
serializer_class = RegionSerializer
#urls.py
router = routers.DefaultRouter()
router.register(r'countries', CountryViewSet)
router.register(r'regions', RegionViewSet)
So for some reason I got this error when I try to access to this url ( http://192.168.33.30:5000/regions/ ): May not set both read_only and required
What am I missing ?
Thanks a lot for your help !
EDIT
I found one of my problem. I removed the line unique_together = ('slug', 'country') in my Region model. I set the slug field as unique. The second problem is that I had to break my model to make it work.
Rather than specify read-only in the Serializer, do this:
class RegionSerializer(serializers.ModelSerializer):
country = CountrySerializer(required=True, many=False)
class Meta:
model = Region
fields = ('id', 'name', 'slug', 'iso2', 'lng', 'lat', 'country',)
read_only_fields = ('country', )

Categories