Tag search on multiple criterias - django

I'd like to get all Profile where tag='hello' and tag='world'. I tried with Q() query but I don't have the correct result.
models.py
class Tag(models.Model):
name = models.CharField(unique=True, max_length=100)
slug = models.SlugField(unique=True, max_length=100)
def __str__(self):
return self.name
class Meta:
ordering = ['slug']
class Profile(models.Model):
name = models.CharField(max_length=100)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Meta:
ordering = ['name']
views.py
def search(request: HttpRequest):
q_tag_list = request.GET.get('search-tag').split(',')
profile_filter = Q()
for tag in q_tag_list:
profile_filter = profile_filter & Q(tags__slug__startswith=tag)
profiles = Profile.objects.filter(profile_filter)
return render(request, 'list.html', {'profiles': profiles})
sql generated (from django debug toolbar)
SELECT "socialmedia_profile"."id", "socialmedia_profile"."name", "socialmedia_profile"."facebook_name", "socialmedia_profile"."facebook_latest_likes" FROM "socialmedia_profile" INNER JOIN "socialmedia_profile_tags" ON ("socialmedia_profile"."id" = "socialmedia_profile_tags"."profile_id") INNER JOIN "socialmedia_tag" ON ("socialmedia_profile_tags"."tag_id" = "socialmedia_tag"."id") WHERE ("socialmedia_tag"."slug" LIKE '''hello%''' ESCAPE '\' AND "socialmedia_tag"."slug" LIKE '''world%''' ESCAPE '\') ORDER BY "socialmedia_profile"."name" ASC

Related

Django count using in object list

I have two models - Book and Tags connected by ManyToMany. After filtering the list of books, I want to get the list of tags used in these books and the count for each tag.
class Tag(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255)
type = models.CharField(max_length=255, default='tag')
is_showing = models.BooleanField()
using_count = models.IntegerField(default=0)
def __str__(self):
return self.name
class Meta:
constraints = [
models.UniqueConstraint(
fields=['name', 'type'], name='unique_migration_host_combination'
)
]
#property
#lru_cache
def count(self):
cnt = self.book_set.count()
return cnt
class Book(models.Model):
name = models.CharField(max_length=255)
tag = models.ManyToManyField(Tag)
def __str__(self):
return self.name
#property
def tags_count(self):
return self.tag.filter(type='tag').count()
#property
def genres_count(self):
return self.tag.filter(type='genre').count()
#property
def fandoms_count(self):
return self.tag.filter(type='fandom').count()
The last time I manually took out a list of tags from each book and put them in a dictionary, after which I got a dictionary of the number of tags used, which was not very convenient to use in the django template engine

data of foreign keys are not saving in django admin nested inlines

I'm trying to build a list of replicable fields where the order can be interchanged.
To do so I've built three different models Multicap Multitext Multimg which are Inlines of the model Multis which is an Inline of the model Delta.
I'm using django-nested-admin and everything works fine on the admin page, I can add new objects and change their order.
The problem I have is that when I populate the fields, save the model and then check its content, all the data of the text fields are turned into zeros 0.
instead, when I try to save the image I get this error:
AttributeError: 'int' object has no attribute 'field'
models.py
class Multis(models.Model):
name = models.TextField(max_length=50, null=True, blank=True)
delta = models.ForeignKey('Delta', related_name="delta", null=True, on_delete=models.CASCADE)
class Meta:
ordering = ('name',)
def __str__(self):
return str(self.name)
class Multicap(models.Model):
caption = models.TextField(max_length=50, null=True, blank=True)
multic = models.ForeignKey('Multis', related_name="multicap", null=True, on_delete=models.CASCADE)
class Meta:
ordering = ('caption',)
def __str__(self):
return str(self.caption)
class Multimg(models.Model):
img = models.ImageField(upload_to="images", verbose_name='Image', null=True, blank=True,)
multim = models.ForeignKey('Multis', related_name="multimg", null=True, on_delete=models.CASCADE)
class Meta:
ordering = ('img',)
#property
def img_url(self):
if self.img and hasattr(self.img, 'url'):
return self.img.url
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
def get_absolute_url(self):
return reverse('delta-detail', kwargs={'pk': self.pk})
class Multitext(models.Model):
text = tinymce_models.HTMLField(null=True, blank=True)
multit = models.ForeignKey('Multis', related_name="multitext", null=True, on_delete=models.CASCADE)
class Meta:
ordering = ('text',)
def __str__(self):
return str(self.text)
class Delta(models.Model):
heading = models.CharField(max_length=50, null="true")
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ('heading',)
def __str__(self):
return str(self.heading)
def get_absolute_url(self):
return reverse('delta-detail', kwargs={'pk': self.pk})
admin.py
from django.contrib import admin
import nested_admin
from nested_admin import SortableHiddenMixin, NestedTabularInline, NestedModelAdmin, NestedStackedInline
from .models import Delta, Multimg, Multitext, Multicap, Multis
class MimgAdmin(nested_admin.NestedStackedInline):
model = Multimg
sortable_field_name = "img"
extra = 0
class MtxtAdmin(nested_admin.NestedStackedInline):
model = Multitext
sortable_field_name = "text"
extra = 0
class McapAdmin(nested_admin.NestedStackedInline):
model = Multicap
sortable_field_name = "caption"
extra = 0
class MAdmin(nested_admin.SortableHiddenMixin, nested_admin.NestedStackedInline):
model = Multis
sortable_field_name = "name"
extra = 0
inlines = [ McapAdmin, MtxtAdmin, MimgAdmin ]
#admin.register(Delta)
class DeltaAdmin(nested_admin.NestedModelAdmin):
sortable_field_name = "delta"
inlines = [ MAdmin ]
Solved. It was a stupid error related to sortable_field_name
This field needs to be related to a field in the model which has to be formulated this way:
models.py
position = models.PositiveSmallIntegerField("Position", null=True)
admin.py
sortable_field_name = 'position'
This forms a position field that has a basic value of 0. Doing the way I was doing so this value was being substituted for the field I wanted to fill in.
Hope this can help someone occuring in the same error

Django: Set many-to-many value to a model

I am trying to test my Models Project, Category and Tag. I'm running into an issue when trying to add tags to my project model.
It won't allow me to do it in the Project model itself for eg.
self.project = Project.objects.create(
...
tags=Tag.objects.create("HTML5"),
)
Django docs suggest the I do it as below. However I can't "add" the Tag without saving the model and I can't save the model without adding the Tag
Tests
class ProjectTests(TestCase):
def setUp(self):
self.tag = Tag.objects.create(name="HTML5")
self.project = Project(
title="Oaks on Main Shopping Center",
url="www.oaksonmain.co.za",
image=SimpleUploadedFile(
name="test-image.jpg",
content=open(
"static\\images\\test_images\\florian-olivo-4hbJ-eymZ1o-unsplash (1).jpg", "rb"
).read(),
content_type="image/jpeg",
),
description="Beautiful website created for Oaks on Main Shopping Center in Knysna!",
category=Category.objects.create(name="Website"),
)
self.project.save() <- Problem here
self.project.tags.add(self.tag) <- Problem here
def test_project_model(self):
self.assertEqual(f"{self.project.title}", "Oaks on Main Shopping Center")
self.assertEqual(f"{self.project.url}", "www.oaksonmain.co.za")
self.assertEqual(
f"{self.project.description}",
"Beautiful website created for Oaks on Main Shopping Center in Knysna!",
)
self.assertEqual(self.tags.count(), 3)
self.assertEqual(self.category.count(), 1)
self.assertEqual(self.image.count(), 1)
def test_project_listview(self):
resp = self.client.get(reverse("index"))
self.assertEqual(resp.status_code, 200)
self.assertContains(resp, self.project.title)
self.assertTemplateUsed(resp, "page/index.html")
Models
class Project(models.Model):
class Meta:
ordering = ["-id"] # Always show latest projects first
verbose_name_plural = "Projects"
title = models.CharField(max_length=50)
url = models.URLField()
image = models.ImageField(upload_to=f"{title}/")
description = models.TextField()
category = models.ForeignKey("Category", on_delete=models.PROTECT, related_name="categories")
tags = models.ManyToManyField("Tag", verbose_name="tags")
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("index")
class Category(models.Model):
class Meta:
ordering = ["name"]
verbose_name_plural = "Categories"
name = models.CharField(max_length=20)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("index")
class Tag(models.Model):
class Meta:
ordering = ["name"]
verbose_name_plural = "Tags"
name = models.CharField(max_length=10)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("index")
You can first save the tag or the model object, and then later you link the tag as (one of) tags of that Project, so:
html5_tag, __ = Tag.objects.get_or_create(name='HTML5')
self.project = Project.objects.create(
# no tags=…
)
self.project.tags.add(html5_tag)
Your ImageField also should work with a callable for the upload_to=… parameter, so:
class Project(models.Model):
# …
def upload_image(self, filename):
return f'{self.title}/{filename}'
image = models.ImageField(upload_to=upload_image)
# …

How to send info in URL?

I am trying to create a product filter.
I am sending the user choice in URL
if the user select size = L then using request.GET
I am receiving:
{'size': ['L']}
But I want to receive: {'size':{'op':'in','attri':'L'}}
Is this possible?
Please help
my models are
class ProductAttribute(models.Model):
slug = models.SlugField(max_length=50, unique=True)
name = models.CharField(max_length=100)
op = models.CharField(max_length=20,default='in')
class Meta:
ordering = ('slug', )
def __str__(self):
return self.name
def get_formfield_name(self):
return slugify('attribute-%s' % self.slug, allow_unicode=True)
def has_values(self):
return self.values.exists()
class AttributeChoiceValue(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=100)
attribute = models.ForeignKey(
ProductAttribute, related_name='values', on_delete=models.CASCADE)
class Meta:
unique_together = ('name', 'attribute')
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=128)
attributes = HStoreField(default={})
q2 = AttributeChoiceValue.objects.filter(attribute__name='size')
My size filter(filter.py) is:
size = django_filters.ModelMultipleChoiceFilter(queryset=q2.values_list('name', flat=True).distinct(),widget=forms.CheckboxSelectMultiple)
I am currently using the following query to filter my database in views.py
result = Product.objects.all()
for key, value in request.GET:result = result.filter(**{'attributes__{}__in'.format(key): value})
I want to make it
a=request.GET
for key, value in a:
result = result.filter(**{'attributes__{}__{}'.format(key,a['op']): value})
so that if I even use Price range as filter my query filter accordingly will be
attributes__price__range
You can send info to your views via "path converters":
https://docs.djangoproject.com/en/2.0/topics/http/urls/#path-converters
Or using regular expressions:
https://docs.djangoproject.com/en/2.0/topics/http/urls/#using-regular-expressions

django-piston: how to get values of a many to many field?

I have a model with ManyToManyField to another model. I would like to get all the info on a particular record (including the related info from other models) return by JSON.
How to get django-piston to display those values? I would be happy with just primary keys.
Or can you suggest another option ?
I may be wrong, but this should do it:
class PersonHandler(BaseHandler):
model = Person
fields = ('id', ('friends', ('id', 'name')), 'name')
def read(self, request):
return Person.objects.filter(...)
You need to define a classmethod on the handler that returns the many-to-many data, I don't believe Piston does this automatically.
class MyHandler(BaseHandler):
model = MyModel
fields = ('myfield', 'mymanytomanyfield')
#classmethod
def mymanytomanyfield(cls, myinstance):
return myinstance.mymanytomanyfield.all()
My code:
Models:
class Tag(models.Model):
"""docstring for Tags"""
tag_name = models.CharField(max_length=20, blank=True)
create_time = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.tag_name
class Author(models.Model):
"""docstring for Author"""
name = models.CharField(max_length=30)
email = models.EmailField(blank=True)
website = models.URLField(blank=True)
def __unicode__(self):
return u'%s' % (self.name)
class Blog(models.Model):
"""docstring for Blogs"""
caption = models.CharField(max_length=50)
author = models.ForeignKey(Author)
tags = models.ManyToManyField(Tag, blank=True)
content = models.TextField()
publish_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s %s %s' % (self.caption, self.author, self.publish_time)
Handle:
class BlogAndTagsHandler(BaseHandler):
allowed_methods = ('GET',)
model = Blog
fields = ('id' 'caption', 'author',('tags',('id', 'tag_name')), 'content', 'publish_time', 'update_time')
def read(self, request, _id=None):
"""
Returns a single post if `blogpost_id` is given,
otherwise a subset.
"""
base = Blog.objects
if _id:
return base.get(id=_id)
else:
return base.all() # Or base.filter(...)
Works petty good.