I want to list related categories saved on a db field called "related"
my code
def category(request, slug):
related = Article.objects.filter(slug__icontains=slug).values('related').first()
return render(request,'category.html',{'related':related}
y try with:
option 1:
In case of a return, a None on related I assign only the category
Article.objects.filter(Q(slug__icontains=slug) | Q(category__icontains=slug))
option 2:
if related is None:
related = Article.objects.filter(category__icontains=slug).values('category').first()
else:
related = related.get('related').split(',')
error:
'NoneType' object has no attribute 'get'
In my DB I checked with the following query:
SELECT * FROM `article` WHERE slug like '%internet%'
And I get 0 records, so the error is coherent
But I don't see how to assign in that case
SELECT * FROM `article` WHERE category like '%internet%'
where I have 22 results
model:
class Article(models.Model):
category = models.CharField(max_length=2000, blank=True, null=True)
related = models.CharField(max_length=2000, blank=True, null=True)
text = models.CharField(max_length=2000, blank=True, null=True)
slug= models.SlugField(max_length=255, unique=True)
class Meta:
managed = False
db_table = 'article'
def __str__(self):
return u'%s %s %s %s' % (self.categoria,self.related, self.text, self.slug)
option 3:
Article.objects.filter(Q(slug__icontains=slug) | Q(category__icontains=slug)).values_list("related", flat=True).distinct()
error too many values to unpack (expected 2)
error line 37 with this:
relateds = related.get('related').split(',')
all the process:
def category(request, slug):
related = Article.objects.filter(Q(slug__icontains=slug) | Q(category__icontains=slug)).values('related').distinct()
temp=[]
for x in relateds:
temp.append(x.replace(" ","-").replace("é","e"))
relateds=temp
With option 2 you could try it this way
related = Article.objects.filter(slug__icontains=slug).values('category').first()
if not related:
related = Article.objects.filter(category__icontains=slug).values('category').first()
If I understand correctly what you wanted to do, you can use option 1 with values_list method.
Article.objects.filter(Q(slug__icontains=slug) | Q(category__icontains=slug)).values_list("related", flat=True).distinct()
This query will return all unique related fields for the slug you have searched. You can also check and remove empty values in filter by related__isnull=False
The views.py file should look like as below finally. I've corrected the typos and indentations.
def category(request, slug):
if slug is None:
related = Article.objects.filter().values_list('related', flat=True).distinct()
else:
related = Article.objects.filter(Q(slug__icontains=slug) | Q(category__icontains=slug)).values_list('related', flat=True).distinct()
relateds=[]
for x in related:
relateds.append(x.replace(" ","-").replace("é","e"))
return render(request,'category.html',{'related': relateds})
Related
so,i have a List of all mobile phones whose brand name is one of the incoming brands. The desired brand names will be entered. The number of entries is unknown and may be empty. If the input is empty, the list of all mobile phones must be returned.
model:
from django.db import models
class Brand(models.Model):
name = models.CharField(max_length=32)
nationality = models.CharField(max_length=32)
def __str__(self):
return self.name
class Mobile(models.Model):
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
model = models.CharField(max_length=32, default='9T Pro', unique=True)
price = models.PositiveIntegerField(default=2097152)
color = models.CharField(max_length=16, default='Black')
display_size = models.SmallIntegerField(default=4)
is_available = models.BooleanField(default=True)
made_in = models.CharField(max_length=20, default='China')
def __str__(self):
return '{} {}'.format(self.brand.name, self.model)
query:
from django.db.models import F, Q
def some_brand_mobiles(*brand_names):
query = Mobile.objects.filter(Q(brand__name__in=brand_names) | ~Q(brand__name=[]))
return query
If the input is empty, the list of all mobile phones will be returned, but i cant use *brand_names to return the list.
for example
query = Mobile.objects.filter(Q(brand_name_in=['Apple', 'Xiaomi']))
return query
and
query = Mobile.objects.filter(~Q(brand__name=[]))
return query
Both of these conditions work by example alone, but it does not check both conditions with the function I wrote.
how to fix it ?
It is simpler to just check the list of brand_names and filter if it contains at least one element:
def some_brand_mobiles(*brand_names):
if brand_names:
return Mobile.objects.filter(brand__name__in=brand_names)
else:
return Mobile.objects.all()
Try this solution:
def some_brand_mobiles(*brand_names):
queryset = Mobile.objects.all()
if brand_names:
queryset = queryset.filter(brand__name__in=brand_names)
return queryset
In that way you can add more filters based on any other condition over the queryset.
I am sorting a query on a timefield from a manytomany object but have trouble during pagination.
models.py:
class Validated(models.Model):
job_id_list = models.ManyToManyField(JobId , related_name='JobId', blank=True)
class JobId(models.Model):
user = models.ForeignKey(User, blank=True, null=True, default=None)
job_time = models.DateTimeField(auto_now_add=True)
views.py:
results_list = Validated.objects.filter(job_id_list__user=request.user).\
distinct().order_by('-job_id_list__job_time')
My problem is that pagination is messed up and I get duplicates in my pagination output, even when the query output is ok. (other have this problem too)
I tried several solutions but my issue does not get solved as sorting is bases on a field from a many-to-many object order_by('job_id_list__job_time')
I was thinking of a work-around through creating an annotation to my model by the use of a Model.Manager. Inside this annotation, i try to add the job_time which is a result of a function inside the model. In that way, the job_time would be easily accessible:
for i in result_list:
job_time_from_model = result_list[i].job_time
I would do this as followed but I don't know how to incorporate the %%function logic%% inside the annotation.
Is this even possible in this way or is another approach required?
models.py:
class ValidatedManager(models.Manager):
**%%function-logic%%**
def date(self, user, id):
xlinkdatabase_validated_object = self.get(id=id)
job_id_list = xlinkdatabase_validated_object.\
job_id_list.all().order_by('-job_time')
date_added = None
for item in job_id_list:
if item.user == user:
date_added = item.job_time
break
return date_added
def get_queryset2(self, user):
qs = super(XlinkdatabaseValidatedManager, self).\
get_queryset().annotate(job_date= **%%function-logic%%**, output_field=DateTimeField())
return qs
views.py:
results_list = xlinkdatabase_validated.objects.get_queryset2(request.user).\
filter(job_id_list__user=request.user).distinct().order_by('-job_date')
I have such a model, in my django application. I want to draw only one field of this model and put them in the view. My solution below does not work:
obj = Text.objects.get(subsID)
My model
result = braintree.Subscription.create({
"payment_method_token": payment_method_token,
"plan_id": "67mm"
})
subscription_id = result.subscription.id
class Text(models.Model):
title = models.CharField(max_length=255)
text = models.TextField()
date_from = models.DateTimeField('date from', blank=True, null=True)
date_to = models.DateTimeField('date to', blank=True, null=True)
subsID = models.CharField(default=subscription_id, max_length=255)
def __unicode__(self):
return self.title
My view
def get_history(request):
subscription_id = Text.objects.filter(subsID)
history = braintree.Subscription.find(subscription_id)
return render(request, "sheet/history.html", {"history": history})
Generally, When filter or get, you have to put query inside it, like
subscription_id = Text.objects.filter(fieldname="searchterm")
This will return a queryset.So to view this
subscription_id.values() #returns a list of objects(dicts)
If you want to get only subsID
subscription_id.values("subsID")
This also return you list which contains
[{"subsID":"value"}, {"subsID":"value"} ....]
If you want to get only values
subscription_id.values_list("subsID", flat=True)
This will return like
["value", "value", ....]
You have to equal subsID to the value you want to find.
subscription_id = Text.objects.filter(subsID=<your subscrition id variable>)
pay attention this will return a list []
subscription_id = Text.objects.get(subsID=<your subscrition id variable>)
This will return an object
Link
You can't use the model in the view, you need to use the ModelForm or Form.
Once you use that one, you can specify which field is active or not or simply setting the attribute in the ModelForm,
exclude=['paramiter_name']
and it's done.
Good luck.
I have the following database model -
class ObjectDetail(models.Model):
title = models.CharField()
img = models.ImageField()
description = models.TextField()
uploaded_by = models.ForeignKey(User, related_name='uploaded_by')
class Vote(models.Model):
vote_type = models.BooleanField(default = False)
voted_by = models.ForeignKey(User, related_name='voted_by')
voted_for = models.ForeignKey(User, related_name='voted_for')
shared_object = models.ForeignKey(ObjectDetail, null=True, blank=True)
dtobject = models.DateTimeField(auto_now_add=True)
Now, in my views I want to get the number of upvotes and downvotes for each of the objects.
One way of doing it would be to add a function under class ObjectDetails
as follows -
#property
def upvote(self):
upvote = Vote.objects.filter(shared_object__id = self.id,
vote_type = True).count()
return upvote
#property
def downvote(self):
downvote = Vote.objects.filter(shared_object__id = self.id,
vote_type = False).count()
return downvote
But this would, cause two queries for each of the object, present in the database.
Another method would be to use annotate
obj = ObjectDetail.objects.select_related().filter(FILTER_CONDITION).annotate(upvote=Count('vote'), downvote=Count('Vote')).order_by('-shared_time')
The above statement is wrong in a sense that it just gives me the counts of votes, irrespective of upvotes and downvotes.
if you see into the model, you can get upvote by filtering vote__vote_type = True and a downvote by vote__vote_type=False
How to add these two conditions/filters in the query statement?
So my prime objective is to get the two values of upvote and downvote for each of the items, with making least db queries, such that in the template, if i do
{{ obj.upvote }} I can get the number of upvote on the object, and the similar for downvote.
Please let me know, thanks.
Did you try with values() to group the different vote_types?
https://docs.djangoproject.com/en/dev/topics/db/aggregation/#values
Vote.objects.select_related().filter(FILTER_CONDITION).values('shared_object', 'vote_type').annotate(vote_count=Count('vote_type'))
At this point you can use regroup in the template to loop on ObjectDetailss
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#regroup
I am working on a library system to manage certain items in our office, I don't need a full-blown integrated library system so I decided to hand roll one with Django.
Below is a simplified version of my model:
class ItemObjects(models.Model):
# Static Variables
IN_STATUS = 'Available'
OUT_STATUS = 'Checked out'
MISSING = 'Missing'
STATUS_CHOICES = (
(IN_STATUS, 'Available'),
(OUT_STATUS, 'Checked out'),
(MISSING, 'Missing'),
)
# Fields
slug = models.SlugField(unique=True)
date_added = models.DateField(auto_now_add=True)
last_checkin = models.DateTimeField(editable=False, null=True)
last_checkout = models.DateTimeField(editable=False, null=True)
last_activity = models.DateTimeField(editable=False, null=True)
status = models.CharField(choices=STATUS_CHOICES, default=IN_STATUS, max_length=25)
who_has = models.OneToOneField(User, blank=True, null=True)
times_out = models.PositiveIntegerField(default=0, editable=False)
notes = models.CharField(blank=True, max_length=500)
history = models.TextField(blank=True, editable=False)
pending_checkin = models.BooleanField(default=False)
pending_transfer = models.BooleanField(default=False)
At first I was using a method on ItemObject to process checking out an item to a user and who_has was an EmailField because I couldn't get a CharfField to populate with the logged in user's name, but I figured using a OneToOneField is probably closer to the "right" way to do this.. While who_has was an EmailField, the following method worked:
def check_out_itemobject(self, user):
user_profile = user.get_profile()
if self.status == 'Available' and self.who_has == '':
self.status = 'Checked out'
self.who_has = user.email
self.last_checkout = datetime.datetime.now()
self.last_activity = datetime.datetime.now()
self.times_out += 1
if self.history == '':
self.history += "%s" % user_profile.full_name
else:
self.history += ", %s" % user_profile.full_name
if user_profile.history == '':
user_profile.history += self.title
else:
user_profile.history += ", %s" % self.title
else:
return False # Not sure is this is "right"
user_profile.save()
super(ItemObjects, self).save()
Now that I am using a OneToOneField this doesn't work, so I started looking at using a subclass of ModelForm but none of the cases I saw here on SO seemed to apply for what I am trying to do; my form would be a button, and that's it. Here are some of the questions I looked at:
Django: saving multiple modelforms simultaneously (complex case)
(Django) (Foreign Key Issues) model.person_id May not be NULL
django update modelform
So was I on the right track with a sort of altered save() method, or would a ModelForm subclass be the way to go?
EDIT/UPDATE: Many thanks to #ChrisPratt!
So I am trying to get Chris Pratt's suggestion for showing ItemHistory to work, but when I try to render it on a page I get an AttributeError that states "'User' object has no attribute 'timestamp'". So my question is, why is it complaining about a User object when last_activity is an attribute on the ItemObject object ?
My view:
#login_required
def item_detail(request, slug):
item = get_object_or_404(Item, slug=slug)
i_history = item.last_activity
user = request.user
return render_to_response('items/item_detail.html',
{ 'item' : item,
'i_history': i_history,
'user' : user })
I do not see why a User object is coming up at this point.
EDIT2: Nevermind, history is clearly a M2M field whose target is User. That's why!
Assuming users will log in and check out books to themselves, then what you most likely want is a ForeignKey to User. A book will only have one User at any given time, but presumably Users could check out other items as well. If there is some limit, even if the limit is actually one per user, it would be better to validate this in the model's clean method. Something like:
def clean(self):
if self.who_has and self.who_has.itemobject_set.count() >= LIMIT:
raise ValidationError('You have already checked out your maximum amount of items.')
Now, you checkout method has a number of issues. First, status should be a defined set of choices, not just random strings.
class ItemObject(models.Model):
AVAILABLE = 1
CHECKED_OUT = 2
STATUS_CHOICES = (
(AVAILABLE, 'Available'),
(CHECKED_OUT, 'Checked Out'),
)
...
status = models.PositiveIntegerField(choices=STATUS_CHOICES, default=AVAILABLE)
Then, you can run your checks like:
if self.status == self.STATUS_AVAILABLE:
self.status = self.STATUS_CHECKED_OUT
You could use strings and a CharField instead if you like, as well. The key is to decouple the static text from your code, which allows much greater flexibility in your app going forward.
Next, history needs to be a ManyToManyField. Right now, your "history" is only who last checked the item out or what the last item the user checked out was, and as a result is pretty useless.
class ItemObject(models.Model):
...
history = models.ManyToManyField(User, through='ItemHistory', related_name='item_history', blank=True)
class ItemHistory(models.Model):
CHECKED_OUT = 1
RETURNED = 2
ACTIVITY_CHOICES = (
(CHECKED_OUT, 'Checked Out'),
(RETURNED, 'Returned'),
)
item = models.ForeignKey(ItemObject)
user = models.ForeignKey(User)
activity = models.PostiveIntegerField(choices=ACTIVITY_CHOICES)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-timestamp'] # latest first
Which then allows you to get full histories:
some_item.history.all()
some_user.item_history.all()
To add a new history, you would do:
ItemHistory.objects.create(item=some_item, user=some_user, activity=ItemHistory.CHECKED_OUT)
The auto_now_add attribute ensures that the timestamp is automatically set when the relationship is created.
You could then actually get rid of the last_checkout and last_activity fields entirely and use something like the following:
class ItemObject(models.Model):
...
def _last_checkout(self):
try:
return self.history.filter(activity=ItemHistory.CHECKED_OUT)[0].timestamp
except IndexError:
return None
last_checkout = property(_last_checkout)
def _last_activity(self):
try:
return self.history.all()[0].timestamp
except IndexError:
return None
last_activity = property(_last_activity)
And, you can then use them as normal:
some_item.last_checkout
Finally, your checkout method is not an override of save so it's not appropriate to call super(ItemObject, self).save(). Just use self.save() instead.