adding more then one data in Many to many in Django - python

I have a project I want to add() more then one data to ManyToMany field
class Product(models.Model):
name = models.models.CharField(Name)
class Tags(models.Model):
product_of_names = models.ForeignKey(Product)
tag_name = models.models.CharField()
class Group(models.Model):
tag_group = models.ManyToManyField(Tags)
views.py
def home(request, pk):
product_name = Product.objects.get(pk=pk)
tag = Tags.objects.filter(product_of_names=product_name)
print(tag.id)
>>> 1
>>> 2
>>> 3
insert_data = Group.objects.create()
insert_data.tag_group.add(tag)
insert_data.save()
it add just one I want to add them all in ManyToMany
Thanks for any help

You can just add more objects into .add() method.
insert_data.tag_group.add(tag_1, tag_2, tag_3)
or shorter
insert_data.tag_group.add(*tags)
You can also pass a list using .set()
list_of_tags = list(Tags.objects.filter(product_of_names=product_name))
insert_data.tag_group.set(list_of_tags)
Read the docs: https://docs.djangoproject.com/en/4.1/ref/models/relations/#django.db.models.fields.related.RelatedManager.add

Related

Django OneToOneField to multiple models and multi OneToOneField

I have the following models:
class District(models.Model):
pk_district = models.AutoField(primary=True)
class Block(models.Model):
pk_block = models.AutoField(primary=True)
class Community(models.Model):
pk_community = models.AutoField(primary=True)
class RelateOne(models.Model):
pk_object = models.OneToOneField('District or Block or Community')
name = models.CharField()
class RelateTwo(models.Model):
pk_object = models.OneToOneField('District or Block or Community')
name = models.CharField()
I want the RelateOne or RelateTwo model to associate District or Block or Community, and then I can use it like this:
district = District.objects.get(pk=1)
district.relate_one.name
district.relate_two.name
block = Block.objects.get(pk=1)
block.relate_one.name
block.relate_two.name
Block.objects.select_related('relate_one','relate_two')
How should I set up the model correctly?
You can use GenericForeignKey from django docs: https://docs.djangoproject.com/en/3.2/ref/contrib/contenttypes/
I would specify the key in Block or District to ensure there is only "one" block per generic relation
Make sure to specify related attributes to get the reverse relationship, although in your case you don't need that.
so it would look something like this:
class Community(models.Model):
pk_community = models.AutoField(primary=True)
content_type = models.ForeignKey(ContentType,
on_delete=models.CASCADE)
object_id = models.CharField(max_length=100)
content_object = GenericForeignKey("content_type", "object_id")
class RelateOne(models.Model):
name = models.CharField(primary_key=)
class RelateTwo(models.Model):
name = models.CharField(primary_key=True)
# to use it would be something like this:
rel1= RelationOne(name="john")
rel2= RelationTwo(name="dave")
com_data={content_object=rel1,**your_other_data}
com=Community(**com_data)
com.save
#then to access relation:
com.content_object.rel_one_or_two_field....
# remember to be careful as these are generic, it's best to let a
#serializer take care of this.

Django-Tables2 add extra columns from dictionary

I apologize if this question has been asked before but I couldn't find my specific use case answered.
I have a table that displays basic product information. Product details such as price, number of sales, and number of sellers are scraped periodically and stored in a separate database table. Now I want to display both the basic product information and scraped details in one table on the frontend using tables2. To do this, I wrote a function in my Product model to fetch the latest details and return them as a dictionary this way I can use a single Accessor call.
# models.py
class Product(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=256)
brand = models.ForeignKey(Brand)
category = models.CharField(max_length=128, choices=CATEGORY_CHOICES)
def __unicode__(self):
return self.name
def currentState(self):
currentDetailState = ProductDetailsState.objects.filter(
product=self
).latest('created_at')
# return current details as a dictionary
return {
price: currentDetailState.price,
num_sellers: currentDetailState.num_sellers,
num_sales: currentDetailState.num_sales
}
class ProductDetailsState(models.Model):
product = models.ForeignKey(Product)
created_at = models.DateTimeField(auto_now_add=True)
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
num_sellers = models.IntegerField(null=True)
num_sales = models.IntegerField(null=True)
def __unicode__(self):
return self.created_at
# tables.py
class ProductTable(tables.Table):
productBrand = tables.Column(
accessor=Accessor('brand.name'),
verbose_name='Brand'
)
currentRank = tables.Column(
accessor=Accessor('currentRank')
)
class Meta:
model = Product
...
How do I now use this returned dictionary and split it into columns in my Product table? Is there another way to use an Accessor than how I am doing it?
You can use the Accessor to traverse into the dict, so something like this should work:
class ProductTable(tables.Table):
# brand is the name of the model field, if you use that as the column name,
# and you have the __unicode__ you have now, the __unicode__ will get called,
# so you can get away with jus this:
brand = tables.Column(verbose_name='Brand')
currentRank = tables.Column()
# ordering on the value of a dict key is not possible, so better to disable it.
price = tables.Column(accessor=tables.A('currentState.price'), orderable=False)
num_sellers = tables.Column(accessor=tables.A('currentState.num_sellers'), orderable=False)
num_sales = tables.Column(accessor=tables.A('currentState.num_sales'), orderable=False)
class Meta:
model = Product
While this works, sorting is also nice to have. In order to do that, your 'currentState' method is a bit in the way, you should change the QuerySet you pass to the table. This view shows how that could work:
from django.db.models import F, Max
from django.shortcuts import render
from django_tables2 import RequestConfig
from .models import Product, ProductDetailsState
from .tables import ProductTable
def table(request):
# first, we make a list of the post recent ProductDetailState instances
# for each Product.
# This assumes the id's increase with the values of created_at,
# which probably is a fair assumption in most cases.
# If not, this query should be altered a bit.
current_state_ids = Product.objects.annotate(current_id=Max('productdetailsstate__id')) \
.values_list('current_id', flat=True)
data = Product.objects.filter(productdetailsstate__pk__in=current_state_ids)
# add annotations to make the table definition cleaner.
data = data.annotate(
price=F('productdetailsstate__price'),
num_sellers=F('productdetailsstate__num_sellers'),
num_sales=F('productdetailsstate__num_sales')
)
table = ProductTable(data)
RequestConfig(request).configure(table)
return render(request, 'table.html', {'table': table})
This simplifies the table definition, using the annotations created above:
class ProductTable(tables.Table):
brand = tables.Column(verbose_name='Brand')
currentRank = tables.Column()
price = tables.Column()
num_sellers = tables.Column()
num_sales = tables.Column()
class Meta:
model = Product
You can find the complete working django project at github

Insert multiple keywords in one field

My question is how i can insert multiple keywords in one django field and show them in a template like stackoverflow tags.
Models:
class Jobs(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(blank=True, default='')
company = models.ForeignKey(Company, on_delete=models.CASCADE)
tags = ?????
Create another class and use many-to-many relationship between jobs class (tags) and new class:
class Tags(models.Model):
tag_name=models.CharField()
In jobs class
tags=models.ManyToManyField(Tags)
For show in template you can use for loop, etc.
Make it a Comma separated value.
class Jobs(models.Model):
tags = models.TextField()
def tag_list(self):
return self.tags.split(",")
def add_tag(self, tag_str):
current_tags = self.tag_list()
current_tags.append(tag_str)
current_tags = set(current_tags)
new_tag_string = ",".join(current_tags)
self.tags = new_tag_string
# you could save the model now or let caller save it outside of this method. I suggest letting caller save the model.
def remove_tag(self, tag_str):
current_tags = self.tag_list()
current_tags.remove(tag_str)
new_tag_string = ",".join(current_tags)
self.tags = new_tag_string
# you could save the model now or let caller save it outside of this method. I suggest letting caller save the model.

Django filter on values of child objects

I have the following (simplified) data model:
class Article(Model):
uuid = models.CharField(primary_key=True, max_length=128)
class Attribute(Model):
uuid = models.CharField(primary_key=True, max_length=128)
article = models.ForeignKey(Article, related_name='attributes')
type = models.CharField(max_length=256)
value = models.CharField(max_length=256)
An example usage would be an article with an attribute attached to it with type="brand" and value="Nike". Now I want to write an API which can get all articles with a certain brand, but I can't seem to write the filter for it. This is what I have so far:
class PhotobookFilter(df.FilterSet):
brand = df.CharFilter(method='filter_brand')
class Meta:
model = Article
def filter_brand(self, queryset, name, value):
return queryset.filter('order__attributes')
class PhotobookViewSet(AbstractOrderWriterViewSet):
queryset = Article.objects.all()
serializer_class = ArticlePhotobookSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = PhotobookFilter
The line with queryset.filter is obviously not correct yet. I need to create a filter here that returns all articles that contain an attribute with type="brand" and value=value. How would I do this?
Are you sure you want to condense both lookups (type and value of Attribute) into one filter? Why not allow filtering on both fields separately?
E.g.
class PhotobookFilter(df.FilterSet):
type = df.CharFilter(method='filter_type')
value = df.CharFilter(method='filter_value')
class Meta:
model = Article
def filter_type(self, queryset, name, value):
return queryset.filter(**{'attributes__type': value})
def filter_value(self, queryset, name, value):
return queryset.filter(**{'attributes__value': value})
And now a query like ?type=brand&value=Nike should work.
Obviously you could condense both conditions into one filter and for example hard code the band part:
class PhotobookFilter(df.FilterSet):
brand = df.CharFilter(method='filter_brand')
def filter_brand(self, queryset, name, value):
return queryset.filter(**{'attributes__type': 'brand', 'attributes__value': value})
But keeping them separate feels way more flexible.
You could also filter in reverse like this:
class PhotobookFilter(df.FilterSet):
brand = df.CharFilter(method='filter_brand')
class Meta:
model = Article
def filter_brand(self, queryset, name, value):
articles = Attribute.objects.filter(type="brand", value=value).values_list('article_id', flat=True)
return queryset.filter(id__in=articles)
This will create subquery for Attribute, which will still be one sql request in the end
Use search_fields .For correct result rename your 'type' attribute name http://www.codesend.com/view/09ca65d42248fe1d89d07ce151f4f050/

Making a smart class factory in Django

I've been trying to figure this out for a while now with little success. I'm attempting to write a class factory that plays nice with Django's ORM, so that I can take a model schema like this:
Product
SubclassOfProduct0
SubclassOfProduct1
....
To work like this:
Product.objects.get(pk=7) // returns the result of SubclassOfProduct0(pk=7)
Product.objects.filter(propname="w00t") // returns a QuerySet of Product objects
So I was thinking something like this:
class ProductManager(models.Manager):
def get(self, *a, **kwa):
# Get the id from Products (somehow)
if product.type == Product.TYPE_SUBCLASS0:
return ProductSubClass0.objects.get(pk=kwa["pk"])
class Product(models.Model):
TYPE_SUBCLASS0 = 0
TYPE_SUBCLASS1 = 1
objects = ProductManager()
def __init__(self, *a, **kwa):
self.set_defaults()
def set_defaults(self):
pass
class ProductSubClass0(models.Model):
def set_defaults(self):
self.type == self.TYPE_SUBCLASS0
...but I don't know how to do it "right". Can someone shed some light here?
Django Tagging has a great example in the models.py as to how it figures out the content type of specific classes. I'm currently using the pattern in another module I developed with permissions.
You could just subclass your Product, as documented here: http://docs.djangoproject.com/en/1.2/topics/db/models/#model-inheritance
class OtherProduct(Product):
battery_life = …
Maybe also make Product an abstract base class if you don’t need to use it directly.
You could use entity framework with generic relations. For example, in models.py:
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
# Product
class Product(models.Model):
name = models.CharField(max_length=128)
pub_date = models.DateTimeField('date published', null=True)
productDescription = models.CharField(max_length=400)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
#Shirt Product type
class ShirtProduct(models.Model):
product = generic.GenericRelation(Product)
#Book Product type
class BookProduct(models.Model):
product = generic.GenericRelation(Product)
....
For search one product id, you can use this method in your ProductManager:
product = generic.GenericRelation(Product,
content_type_field='content_type_fk',
object_id_field='object_primary_key')
(reverse generic relations in the same section of djangoproject page)

Categories

Resources