I am building a Blog App and I am trying to sort or order_by in list which contains multiple queries.
models.py
class BlogPost(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=30)
date = models.DateTimeField(auto_now_add=True)
class Comments(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
blog_of = models.ForeignKey(BlogPost, on_delete=models.CASCADE)
body = models.CharField(max_length=30, default='')
date_added = models.DateTimeField(auto_now_add=True)
views.py
def mypage(request):
query_1 = list(BlogPost.objects.filter(user=request.user).order_by('-date'))
query_2 = list(Comment.objects.filter(user=request.user).order_by('date_added'))
results = sorted(chain(query_1, query_2),key=attrgetter('date') , reverse=True)
context = {'results':results}
return render(reques, 'mypage.html', context)
But is showing
'Comment' object has no attribute 'date'
And I think this is because date field name is different in both model and i am sorting with only one, But i have no idea how can I sort with different field name.
Any help would be much Appreciated. Thank You
Or just add it as a property:
class Comments(models.Model): # do NOT give a model a plural name!
# ....
#property
def date(self):
return self.date_added
# or if it is a datetimefield
# return self.date_added.date()
ALso you can just write a more customized sorting key (e.g. in case the involved models are from third-party apps).
def order(obj):
try:
return obj.date
except AttributeError:
return obj.date_added
# ...
results = sorted(chain(query_1, query_2), key=order, reverse=True)
Related
Trying to create a column in my model called, stock_count, that finds the sum of the total string objects in my ArrayField(), aka stock_list. Here is my function.
def total_stocks_calc(self):
self.stock_count = Bucket.objects.aggregate(Sum('stock_list', distinct=True))
self.save()
However it doesn't seem to be doing anything, no calculating, leaving the field blank in my model, admin page, and DRF interface...
EDIT: updated post with new implementation.
Here is my model.
class Bucket(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='buckets')
users = models.ManyToManyField(settings.AUTH_USER_MODEL)
category = models.CharField(max_length=30, choices=category_options)
name = models.CharField(max_length=35)
created = models.DateTimeField(default=timezone.now)
slug = models.SlugField(unique=True, blank=True)
stock_count = models.IntegerField(blank=True, null=True)
stock_list = ArrayField(models.CharField(max_length=6,null=True),size=30,null=True)
about = models.CharField(max_length=75)
objects = models.Manager()
bucketobjects = BucketObjects()
class Meta:
ordering = ('-created',)
def total_stocks_calc(self):
self.stock_count = Bucket.objects.annotate(stock_count=F('stock_list__len'))
self.save()
def __unicode__(self):
return self.stock_list
Would like to know the proper way to count total items in ArrayField(), thank you in advance.
The ArrayField provides the len lookup field, through that you can get the count
like
from django.db.models import F
Bucket.objects.annotate(stock_count=F('stock_list__len'))
It's my first time creating a Django website with models, and in my first attempt to insert data into my table I'm getting this error.
My models are as follows:
class User(AbstractUser):
pass
#https://docs.djangoproject.com/en/3.1/topics/auth/default/
class Listing(models.Model):
listingID = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="listID")
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name="myListing", null=True)
watchers = models.ManyToManyField(User, blank=True, related_name="watchlist")
title = models.CharField(max_length=30)
description = models.TextField()
creation_date = models.DateField(auto_now=True)
img_url = models.URLField()
active = models.BooleanField(default=True)
def __str__(self):
return f"{self.title}"
class Bid(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.SET_NULL, related_name="bidsMadeOnMe", null=True, blank=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, related_name="myBids", null=True)
price = models.FloatField()
creation_date = models.DateField(auto_now=True, null=True)
def __str__(self):
return f"Bid={self.price}"
and the view that handles the form submission is this one:
#login_required
def create_listing(request):
if request.method == "POST":
user = User.objects.get(username=request.user.username)
l = Listing(created_by=user,
title=request.POST["title"],
description=request.POST["desc"],
# https://stackoverflow.com/questions/12176585/handling-dates-over-request-get
creation_date=models.DateTimeField(auto_now_add=True),
img_url=request.POST["image_url"]
)
l.save()
b = Bid(l,
user,
request.POST["initial_bid"],
models.DateTimeField(auto_now_add=True)
)
b.save()
return render(request, "auctions/index.html")
I know the problem is the way I'm adding the data but I can't fix it. Can someone give me some light?
Your problem (well, several actually) is this:
b = Bid(l, user, request.POST["initial_bid"], models.DateTimeField(auto_now_add=True))
You're constructing a model instance by positional arguments instead of keyword arguments. This can be done, but then the invisible "id" column that has been added to the Bid model, is the first argument.
In Django we never construct models like that, but always use keyword arguments, so we're not depending on field order:
b = Bid(listing=l, user=user, ...))
Once you're solved that, your next problem is the date field.
Don't assign fields to model instances. Fields are class declarations, they don't belong on instances. Fields describe on a class (= a Model), what kind data to expect. On the instance, you assign that data.
In this case, your definition for the field is wrong on the model and on the instance you shouldn't even assign it - it will be automatically filled.
Overall, it feels like you haven't gone through Django's tutorial or did not fully understand the concepts. I suggest you go through it.
I am really stuck on this error and it does not make sense why it does not follow the relationship backward on Registered_Courses on the foreign key for Courses when i use course_set
views.py
def registered_coursesView(request, username):
'''Page to display the registered courses of a user.'''
registeredCourses = Registered_Courses.objects.get(owner = request.user)
courseInfo = registeredCourses.course_set.all()
context = {'registeredCourses': registeredCourses, 'courseInfo':courseInfo}
return render(request, 'safetyCourseApp/registered_courses.html', context)
models.py
class Course(models.Model):
'''Offered Course information.'''
subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
name = models.CharField(max_length=200, primary_key=True)
description = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
start_date = models.DateField()
end_date = models.DateField()
price = models.DecimalField(max_digits=10, decimal_places=2)
capacity = models.IntegerField()
registered_ppl = models.IntegerField()
def __str__(self):
"""Return a string representation of the model."""
return self.name
class Registered_Courses(models.Model):
"""Something specific learned about a Course."""
registered_course = models.ForeignKey(Course, on_delete=models.CASCADE, null=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
def __str__(self):
"""Return a string representation of the model."""
return f'{self.owner}'
Please let me know what you guys think. I cannot think of a reason why this is not working. Thanks!
As you have specified in your models, each Registered_Courses will have a FK to Course, So each Course can have multiple Registered_Courses.
But you are trying to get multiple Course objects from a single Registered_Courses
The backward relationship is something like:
>>> course = Course.objects.first()
>>> course.registered_courses_set
Here i have mentioned my model,serializer and view. Actually im new to this concepts. I don't how to get the last added product.
Models.py
class Products(models.Model):
name = models.CharField(max_length=100)
image = models.CharField(max_length=100, null=True)
categories = models.ArrayModelField(
model_container=Category,
model_form_class=CategoryForm
)
specifications = models.ArrayModelField(
model_container=Specifications,
model_form_class=SpecificationsForm
)
description = models.CharField(max_length=1000)
reviews = models.ArrayModelField(
model_container=Reviews,
model_form_class=ReviewsForm
)
drizzly = models.BooleanField(default=False)
complete = models.BooleanField(default=False)
comment = models.CharField(max_length=500)
click_count = models.IntegerField()
serializer.py
class ProductsSerializer(serializers.ModelSerializer):
class Meta:
model = Products
fields = ('id',
'name',
'image',
'categories',
'specifications',
'description',
'reviews',
'drizzly',
'complete',
'comment',
'click_count')
views.py
class ProductsViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Products.objects.all()
serializer_class = ProductsSerializer
Please tell me how to do that?.
Since the last product have the highest id then you can try like this
last_product = Products.objects.order_by('-id')[0]
What I'm doing here is ordered all the project in reverse order by id then get first element from that.
The easiest way to get last product would be:
Products.objects.last()
With reverse(), you can do : Products.objects.all().reverse()[0]
For first one: Products.objects.first()
Is that what you want?
You need some "last_modified" timestamp field on your model obviously - else you have no way to know when a record has been updated:
import time
class Products(models.Model):
# your existing fields here
last_updated = models.FloatField(
"last_updated",
editable=False,
default=time.time
)
def save(self, *args, **kw):
self.last_updated = time.time()
if "update_fields" in kw:
kw["update_fields"].append("last_updated")
super(Product, self).save(*args, **kw)
and of course generate and pass the migration.
Then you can get the last updated record using QuerySet.latest(*fields):
last_updated_product = Product.objects.latest("last_modified")
I'm not using DRF so I can't tell how to plug this into your ProductsViewSet but there's certainly some documentation available...
Try
from {app_name} import Products
Products.objects.reverse()[0]
Since there is a primary key pk as default in each model created, you can filter specifically using
Products.objects.filter(order_by='pk')
Working with filtering objects by when they are added to the database using a data time field to track the updated time will provide a less error prune way to get the latest objects.
See Also:
Retrieving the latest object, Ordering model objects
models.py
class Products(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=100)
image = models.CharField(max_length=100, null=True)
categories = models.ArrayModelField(
model_container=Category,
model_form_class=CategoryForm
)
specifications = models.ArrayModelField(
model_container=Specifications,
model_form_class=SpecificationsForm
)
description = models.CharField(max_length=1000)
reviews = models.ArrayModelField(
model_container=Reviews,
model_form_class=ReviewsForm
)
drizzly = models.BooleanField(default=False)
complete = models.BooleanField(default=False)
comment = models.CharField(max_length=500)
click_count = models.IntegerField()
class Meta:
# Latest by ascending updated_at.
get_latest_by = "updated_at"
# This will ensure the objects returned are ordered latest to earliest.
ordering = ['-updated_at']
serializer.py
class ProductsSerializer(serializers.ModelSerializer):
class Meta:
model = Products
exclude = ['created_at', 'updated_at']
views.py
class ProductsViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
# Using Products.objects.latest() should return the latest using
# the updated_at DateTimeField.
# Note this will raise `Models.DoesNotExist` if there is no object.
# Using the Model._meta.ordering the queryset should be ordered by
# the `latest` first or you can also use
# `Model.objects.order_by('-updated_at')`
queryset = Products.objects.all()
serializer_class = ProductsSerializer
I'm getting this error:
The object '' has an empty attribute 'posts' and doesn't allow a default or null value.
I'm trying to get the number of 'votes' on a post and return it in my models.py:
class UserPost(models.Model):
user = models.OneToOneField(User, related_name='posts')
date_created = models.DateTimeField(auto_now_add=True, blank=False)
text = models.CharField(max_length=255, blank=True)
def get_votes(self):
return Vote.objects.filter(object_id = self.id)
Here's my resource:
class ViewPostResource(ModelResource):
user = fields.ForeignKey(UserResource,'user',full=True)
votes= fields.CharField(attribute='posts__get_votes')
class Meta:
queryset = UserPost.objects.all()
resource_name = 'posts'
authorization = Authorization()
filtering = {
'id' : ALL,
}
What am I doing wrong?
The attribute value that you have defined isn't proper.
You can achieve what you want in a few ways.
Define a dehydrate method:
def dehydrate(self, bundle):
bundle.data['custom_field'] = bundle.obj.get_votes()
return bundle
Or set the get_votes as property and define the field in resource like so (I recommend this one as it is the most clear):
votes = fields.CharField(attribute='get_votes', readonly=True, null=True)
Or define it this way:
votes = fields.CharField(readonly=True, null=True)
And in the resources define the dehydrate_votes method like so:
def dehydrate_votes(self, bundle):
return bundle.obj.get_votes()