I am trying to create in a nested serializer in Django Rest Framework but I keep getting this error. I know why it's throwing it but, i thought Django would handle the one-to-many relationship.
AttributeError at /api/campaigns
Got AttributeError when attempting to get a value for field ads on serializer CampaignSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Campaign instance.
Original exception text was: 'Campaign' object has no attribute 'ads'.
class Campaign(models.Model):
name = models.CharField(max_length = 30)
type = models.CharField(max_length = 20)
start_date = models.DateField(auto_now=False, auto_now_add=True)
end_date = models.DateField(auto_now=False, auto_now_add=True)
locations = models.CharField(max_length = 30)
budget = models.IntegerField()
land_page = models.URLField()
keywords = models.TextField()
CPM = models.IntegerField()
CPC = models.IntegerField()
description = models.TextField()
commission = models.IntegerField()
pay_off = models.IntegerField()
advertiser = models.ForeignKey(User)
date_time = models.DateField(auto_now=False, auto_now_add=True)
class Meta:
db_table = "campaigns"
class ADS(models.Model):
advertiser = models.ForeignKey(User)
campaign = models.ForeignKey(Campaign)
headline = models.CharField(max_length=50)
description_1 = models.TextField(blank=True)
description_2 = models.TextField(blank=True)
display_url = models.URLField(blank=True)
final_url = models.URLField(blank=True)
mobile_url = models.URLField(blank=True)
class Meta:
db_table = "ads"
These are my serializers
class ADSerializer(serializers.ModelSerializer):
adsImages = AdsImagesSerializer(read_only=True,many=True)
class Meta:
model = ADS
fields = ("headline","description_1","description_2","display_url","final_url","mobile_url","advertiser","adsImages")
class CampaignSerializer(serializers.ModelSerializer):
advertiser = AdvertiserProfile(read_only=True,required=False)
ads = ADSerializer(many=True)
class Meta:
model = Campaign
fields = ("name","type","start_date","end_date","locations","budget","land_page","keywords","CPM","CPC","description","commission","pay_off","ads","advertiser",)
def get_validation_exclusions(self, *args, **kwargs):
exclusions = super(CampaignSerializer,self).get_validation_exclusions()
return exclusions + ['advertiser']
def create(self, validated_data):
ads_data = validated_data.pop('ads')
campaign = Campaign.objects.create(**validated_data)
for ad_data in ads_data:
ADS.objects.create(campaign=campaign, **ad_data)
return campaign
I just fixed this, with a related name in the model
campaign = models.ForeignKey(Campaign, related_name="ads")
I think it didn't worked last time because the reverse relationship was not working without a related_name.
Related
Im working in my Python Django ecommerce project.Now i have 2 classes Item and BookItem :
class Item(models.Model):
item_name = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200,unique=True)
description = models.TextField(max_length=500, blank=True)
price = models.IntegerField()
images = models.ImageField(upload_to='photos/products')
stock = models.IntegerField()
is_available = models.BooleanField(default = True)
category = models.ForeignKey(Category,on_delete = models.CASCADE)
created_date = models.DateTimeField(auto_now=True)
modified_date= models.DateTimeField(auto_now=True)
def __str__(self):
return self.item_name
def get_url(self):
return reverse('item_detail',args=[self.category.slug, self.slug])
class BookItem(Item):
book = models.ForeignKey(Book,on_delete = models.CASCADE)
I want to get BookItem data from the class Item.Anyone knows how to do it ?
Get Book data for all Items
Item.objects.all().values(
"book__book_name",
"book__import_price",
# "class_name__field_name", structure of the query
)
To filter Item data using Book fields
[filter Items where book name is 'bookname']
Item.objects.filter(book__book_name="bookname")
I don't understand why i got this error, I just added a new foreign key property to Rest model and it doesn't work:
Error
TypeError: Direct assignment to the reverse side of a related set is prohibited. Use exercises.set() instead.
I don't know if the name "rest" is causing I already changed the name of the property but I can't make it work.
models.py
class Routine(models.Model):
name = models.CharField(max_length=30)
creation_date = models.DateField(auto_now_add=True)
class Workout(models.Model):
name = models.CharField(max_length=30)
creation_date = models.DateField(auto_now_add=True)
routine = models.ForeignKey(Routine, related_name='workouts', on_delete=models.CASCADE)
class Exercise(models.Model):
index = models.IntegerField()
video_url = models.URLField(max_length=200)
workout = models.ForeignKey(Workout, related_name='exercises', on_delete=models.CASCADE)
class Rest(models.Model):
index = models.IntegerField()
duration = models.IntegerField()
workout = models.ForeignKey(Workout, related_name='rests', on_delete=models.CASCADE)
routine = models.ForeignKey(Routine, related_name='rests', on_delete=models.CASCADE)
serializers.py
class WorkoutSerializer(serializers.ModelSerializer):
exercises = ExerciseSerializer(many=True)
rests = RestSerializer(many=True)
class Meta:
model = Workout
fields = ['id', 'name', 'creation_date', 'exercises', 'rests']
def create(self, validated_data):
exercises_data = validated_data.pop('exercises')
rests_data = validated_data.pop('rests')
workout = Workout.objects.create(**validated_data)
for exercise_data in exercises_data:
Exercise.objects.create(workout=workout, **exercise_data)
for rest_data in rests_data:
Rest.objects.create(workout=workout, **rest_data)
return workout
class RoutineSerializer(serializers.ModelSerializer):
workouts = WorkoutSerializer(many=True)
rests = RestSerializer(many=True)
class Meta:
model = Routine
fields = ['id', 'name', 'creation_date', 'workouts', 'rests']
def create(self, validated_data):
workouts_data = validated_data.pop('workouts')
rests_data = validated_data.pop('rests')
routine = Routine.objects.create(**validated_data)
for workout_data in workouts_data:
Workout.objects.create(routine=routine, **workout_data)
for rest_data in rests_data:
Rest.objects.create(routine=routine, **rest_data)
return routine
Note: IF INFORMATION BELOW IS NOT CLEAR TO UNDERSTAND - PLEASE ASK ME, I WILL UPDATE AND POST INFORMATION YOU NEED | It is important for me
In Warehouse(models.Model) I have amount attribute and
in ChosenProduct(models.Model) - quantity
I'm trying to get amount in Warehouse through chosen_products instance in App_formSerializer to add the quantity of chosen_product
But I can not get the chosen_products objects from instance
--> below Out:
class WarehouseSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField(
source='category_product.category_name')
posted_user = serializers.ReadOnlyField(
source='posted_user.username')
class Meta:
model = Warehouse
fields = ['id', 'category_product', 'category_name', 'condition',
'product_name', 'amount', 'barcode', 'f_price', 'created_at', 'updated_at', 'posted_user']
class ChosenProductSerializer(serializers.ModelSerializer):
product_info = WarehouseSerializer(source='product', read_only=True)
period_info = Product_periodSerializer(source='period', read_only=True)
class Meta:
model = ChosenProduct
exclude = ('app_form',)
class App_formSerializer(serializers.ModelSerializer):
chosen_products = ChosenProductSerializer(many=True)
def update(self, instance, validated_data):
instance.terminated = validated_data.get('terminated', instance.terminated)
if instance.terminated == True :
print('-----------TRUE--------------------')
print(instance.chosen_products)
print('-----------PRINT--------------------')
instance.save()
return instance
class Meta:
model = App_form
fields = '__all__'
Out
-----------TRUE--------------------
creditapi.ChosenProduct.None
-----------PRINT--------------------
QUESTION UPDATED
models.py
class Warehouse(models.Model):
category_product = models.ForeignKey(
Category_product, on_delete=models.CASCADE)
product_name = models.CharField(max_length=200, unique=True)
condition = models.BooleanField(default=False)
amount = models.IntegerField()
barcode = models.BigIntegerField()
f_price = models.CharField(max_length=255, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
posted_user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
def __str__(self):
return self.product_name
class App_form(models.Model):
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,12}$', message="Phone number must be entered in the format: '998981234567'. Up to 12 digits allowed.")
terminated = models.BooleanField(default=False)
name = models.CharField(max_length=150)
phone_number = models.CharField(validators=[phone_regex], max_length=13)
def __str__(self):
return self.surname
class ChosenProduct(models.Model):
product = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
quantity = models.IntegerField()
app_form = models.ForeignKey(App_form, on_delete=models.CASCADE, related_name='chosen_products')
def __str__(self):
return self.product.product_name
If you write instance.chose_products you access the manager, not the QuerySet that contains the items. You can use .all() to obtain the QuerySet with all the objects:
print(instance.chosen_products.all())
If you access a ForeignKey in reverse, you have a manager, since zero, one, or more elements can refer to the instance.
You can for example aggregate over the chose_products, for example if you want to retrieve the number of related chose_products, you can use:
print(instance.chosen_products.count())
I would however advise not store (aggregated) data in the App_form, but aggregate data when you need it. Data duplication is an anti-pattern, and it turns out it is hard to keep data in sync.
I get the following error and can not find how to fix it
Exception Type: TypeError Exception Value: 'EstablishmentType' object
is not iterable
Class Serializer:
class TransactionSerializer(serializers.HyperlinkedModelSerializer):
establishment_from_id = serializers.HyperlinkedRelatedField(view_name='establishment_type', read_only=True, many=True)
class Meta:
model = Transaction
fields = ('id', 'created_date', 'updated_date','establishment_from_id', 'quantity', 'owner_id', 'quantity_missing', 'gps_longitude', 'gps_latitude', 'gps_accuracy', 'type')
Models
class Transaction(models.Model):
created_date = models.DateTimeField()
updated_date = models.DateTimeField()
establishment_from_id = models.ForeignKey(EstablishmentType, related_name="establishment_from")
establishment_to_id = models.ForeignKey(EstablishmentType, related_name="establishment_to")
quantity = models.FloatField()
owner_id = models.ForeignKey(User)
quantity_missing = models.FloatField()
status = models.ForeignKey(TransactionStatus)
gps_longitude = models.CharField(max_length=400)
gps_latitude = models.CharField(max_length=400)
gps_accuracy = models.CharField(max_length=400)
type = models.FloatField()
def __str__(self):
return str(self.id)
class EstablishmentType(models.Model):
name = models.CharField(max_length=200)
#created_by = CreatingUserField(related_name="created_categories")
def __str__(self):
return self.name
Thanks!
Try taking out the many=True from the Serializer. The establishment_from_id is a FK rather than an M2M, thus for each instance it's only going to have one value. If this were the serializers for EstablishmentType then it would make sense to have a many=True
Models:
class Applicant_Skill(models.Model):
user = models.ForeignKey(User)
#applicant = models.ForeignKey(Applicant)
skill = models.ForeignKey('skills_layer.Skill')
active = models.BooleanField(default=True)
class Job_Posting(models.Model):
company = models.ForeignKey('companies_layer.Company', default=-1)
job_posted_by = models.ForeignKey(User, default=-1)
job_title = models.CharField(max_length=100)
job_summary = HTMLField(blank=True)
job_details = HTMLField(blank=True)
no_of_openings = models.IntegerField(default=0)
tags = models.CharField(max_length=200)
experience_min = models.IntegerField(default=0)
experience_max = models.IntegerField(default=0)
job_location = models.ForeignKey('meta_data_layer.Location', blank=True, null=True)
qualification = models.ForeignKey('meta_data_layer.Qualification', default=-1)
specialization = models.ForeignKey('meta_data_layer.Specialization', default=-1)
nationality = models.ForeignKey('meta_data_layer.Nationality', default=-1)
live = models.BooleanField(default=True)
closing_date = models.DateField(default=datetime.date.today())
auto_renew = models.BooleanField(default=False)
active = models.BooleanField(default=True)
class Meta:
verbose_name = "job posting"
def __str__(self):
return self.job_title
Resource:
from tastypie.resources import ModelResource
from job_posting_layer.models import Job_Posting
from companies_layer.models import Company
from django.contrib.auth.models import User
import meta_data_layer
from tastypie import fields
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
resource_name = 'user'
def dehydrate(self, bundle):
bundle.data['logged_user_id'] = bundle.request.user.id
return bundle
class JobListingResource(ModelResource):
#company = fields.ForeignKey(CompanyResource,'company', full=True)
#job_posted_by = fields.ForeignKey(UserResource,'job_posted_by', full=True)
company_name = fields.CharField(attribute="company__company_name", null=True)
company_id = fields.CharField(attribute="company__id", null=True)
user_first_name = fields.CharField(attribute="job_posted_by__first_name", null=True)
user_last_name = fields.CharField(attribute="job_posted_by__last_name", null=True)
user_id = fields.CharField(attribute="job_posted_by__id", null=True)
job_location = fields.CharField(attribute="job_location__location_name", null=True)
job_city = fields.CharField(attribute="job_location__city", null=True)
qualification = fields.CharField(attribute="qualification__qualification_degree", null=True)
specialization = fields.CharField(attribute="specialization__specialization_course", null=True)
nationality = fields.CharField(attribute="nationality__country_name", null=True)
class Meta:
queryset = Job_Posting.objects.all()
resource_name = 'jobs'
Today is the 1st day I am trying Tastypie so please be kind with me :(
The JobListingResource returns all the Job Listings. But I want to get only those Job Listings for which the Tags column contains values from the skill column of the logged in user.
Eg: If user "A" has logged in and has the following skills "python,django,jquery". I want the JobListingResource to return only those records which contains [python/django/jquery] in the tags column.
I'm assuming you know how to do the queries and just need to know where to do it in Tastypie. In your JobListResource override as follows:
def get_object_list(self, request):
# get all the jobs according to the queryset in Meta
base = super(JobListingResource, self).get_object_list(request)
# and add a filter so only users ones appear
user = request.user
skills = query to get all the skills for the user
return base.filter(filter to apply to JobPosting to only return jobs matching skills list)