How to implement a ordered many2many relation in the Django admin - django

Here a sample models I have:
class Category(models.Model):
name = models.CharField(max_length=128)
class Item(models.Model):
name = models,CharField(max_lenght=128)
category = models.ManyToManyField(Category, blank=True,
related_name='item_category',
null=True, through='ItemCategory')
class ItemCategory(models.Model):
item = models.ForeignKey(Item)
category = models.ForeignKey(Category)
order = models.PositiveIntegerField(default=0, blank=True, null=True)
My problem is how do I arrange the order in the admin side? In other words, I need to expand the widget functionality to allow the user to change the order of the selected items and when the form is saved, the selected items will save the item order in ItemCategory.order. I have the form that looks like this:
class CategoryForm(forms.ModelForm):
_items = forms.ModelMultipleChoiceField(
required=True,
label='Items',
queryset=Items.objects.all(),
widget=FilteredSelectMultiple(verbose_name="Items",
is_stacked=False)
)
def __init__(self, *args, **kwargs):
super(FamilyAdminForm, self).__init__(*args, **kwargs)
class Meta:
model = Items

You could use the Meta class:
class Category(models.Model):
# ...
class Meta:
ordering = ['name']

Related

django add parents to field

I have a Product model that has a ManyToMany to Category.
Category has a ForeignKey to itself named parent.
I want to add all parents of selected category to category field.
example for category:
digital appliance->None __ Mobile->digital appliance __ Samsung->Mobile and...
when choose Samsung for category of a product, I want to add Mobile and digital appliance to category
it's my models, the save method doesn't do anything
Class Product:
class Product(models.Model):
STATUS_CHOICES = (
('s', 'show'),
('h', 'hide'),
)
title = models.CharField(max_length=150)
slug = models.SlugField(max_length=170, unique=True)
category = models.ManyToManyField(Category)
thumbnail = models.ImageField(upload_to='images/products', default='images/no-image-available.png')
image_list = ImageSpecField(source='thumbnail', processors=[ResizeToFill(400, 200)], format='JPEG',options={'quality': 75})
image_detail = ImageSpecField(source='thumbnail', processors=[ResizeToFill(1000, 500)], format='JPEG',options={'quality': 100})
description = models.TextField()
inventory = models.IntegerField()
features = models.ManyToManyField(Feature)
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='s')
def __str__(self):
return self.title
class Meta:
verbose_name = "product"
verbose_name_plural = "products"
def save(self, *args, **kwargs):
for cat in self.category.all():
if cat.parent:
self.category.add(cat.parent)
return super(Product, self).save(*args, **kwargs)
objects = ProductManager()
Category and CategoryManager:
class CategoryManager(models.Manager):
def no_parent(self):
return self.filter(parent=None)
def get_parent(self, parent):
return self.filter(parent=parent)
class Category(models.Model):
parent = models.ForeignKey('self', default=None, null=True, blank=True, on_delete=models.SET_NULL,related_name='children')
title = models.CharField(max_length=40)
slug = models.SlugField()
status = models.BooleanField(default=True)
I think it makes more sense to have Foreign Key to category table rather than m2m relation. You can flatten it in the view whenever needed

How to display category name on article model?

I want to render category field on an article in terms of its name(choice). Currently, it is rendered as an Id. Also, I want to be able to update the article model by entering category name(choice) instead of its Id(I am currently doing this). How can I go about implementing this?
This is what I have so far.
Models
class Category(models.Model):
"""
Model for Category
"""
CATEGORY_CHOICES = (
('Sports', 'Sports'),
('Music', 'Music'),
('Drama', 'Drama'),
('Money', 'Money'),
('Movies', 'Movies'),
('Cars', 'Cars'),
('General', 'General'),
)
name = models.CharField(max_length=30, choices=CATEGORY_CHOICES, default='General',null=False, blank=True)
def __str__(self):
return self.name
class Article(models.Model):
"""
Model for an Article
"""
title = models.CharField(max_length=255, null=False, blank=False)
description = models.TextField(null=False, blank=False)
body = models.TextField(null=False, blank=False,)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
Serializers
class ArticleSerializer(serializers.ModelSerializer):
"""
Serializer for Article.
"""
class Meta:
model = Article
fields = ('title','description','body',''category')
class CategorySerializer(serializers.ModelSerializer):
"""
Serializer for Category.
"""
class Meta:
model = Category
fields = ('name',)
Current output
Expected output
You can change your ArticleSerializer to have the category field as a CharField with a source attribute:
class ArticleSerializer(serializers.ModelSerializer):
category = serializers.CharField(source='category.name')
class Meta:
model = Article
fields = ('title','description','body',''category')
To be able to update the Article's category via the name, you have to make sure that name is a unique field for Category. If yes, then you can use a SlugRelatedField.
category = serializers.SlugRelatedField(slug_field='name')

How to create an inline formset with manytomany relation in Django

I want to create an inline formset between Preorder model and Product model. The scenario is that the user will be able to select one or more than one products when he decides to create a preorder. On the other hand a product might be found in one or more than one preorders. With that in mind i created a manytomany relationship.
models.py
class Preorder(models.Model):
client = models.ForeignKey(Client,verbose_name=u'Client')
invoice_date = models.DateField("Invoice date",null=True, blank=True, default=datetime.date.today)
preorder_has_products = models.ManyToManyField(Product, blank=True)
def get_absolute_url(self):
return reverse('preorder_edit', kwargs={'pk': self.pk})
class Product(models.Model):
name = models.CharField("Name",max_length=200)
price = models.DecimalField("Price", max_digits=7, decimal_places=2, default=0)
barcode = models.CharField(max_length=16, blank=True, default="")
eopyy = models.CharField("Code eoppy",max_length=10, blank=True, default="")
fpa = models.ForeignKey(FPA, null=True, blank=True, verbose_name=u'Fpa Scale')
forms.py
class PreorderForm(ModelForm):
class Meta:
model = Preorder
exclude = ('client','preorder_has_products',)
def __init__(self, *args, **kwargs):
super(PreorderForm, self).__init__(*args,**kwargs)
self.fields['invoice_date'].widget = MyDateInput(attrs={'class':'date'})
class ProductForm(ModelForm):
#name = ModelChoiceField(required=True,queryset=Product.objects.all(),widget=autocomplete.ModelSelect2(url='name-autocomplete'))
class Meta:
model=Product
fields = '__all__'
def __init__(self, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
self.fields['name'].label="Name"
self.fields['price'].label="Price"
and finally the inline formset:
PreorderProductFormSet = inlineformset_factory(Preorder, Product,
form=ProductForm, extra=1)
After run I face up the issue:ValueError at /
'intranet.Product' has no ForeignKey to 'intranet.Preorder'
Why this happening since I created a manytomany relation?
One solution is to create a foreign key relationship between Preorder and Product model inside Product model..but I do not want to do that since product model is used in other areas of my project and do not want to mess it up.
Any suggestions?

Use models foreign key _id column as field in django form

When you create a ForeignKey in a django model django also creates a _id column in the database. I'm trying to figure out how to display this value in a django form but can't seem to get it to work. With what I have below the category_id field appears in the form but the value itself doesn't?
marketplace/models.py
class Category(models.Model):
category = models.CharField(null=True)
category_code = models.IntegerField(unique=True)
store/models.py
class Product(models.Model):
created = models.DateTimeField(default=now)
name = models.CharField(max_length=200, unique=True)
category = models.ForeignKey('marketplace.Category', blank=True, null=True, to_field='category_code')
store/forms.py
class Form(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(Form, self).__init__(*args, **kwargs)
self.fields['category_id'] = self.instance.category_id
class Meta:
model = Product
fields = ['name', 'created']

Django form objects filter

I want to associate the drop-down lists material and category
models
class Demande_Expertise(models.Model):
user = models.ForeignKey(User)
material = models.ForeignKey("Material")
categorie = models.ForeignKey("Category")
class Category(models.Model):
name = models.CharField(_('name'), max_length=50)
slug = models.SlugField()
expert = models.ForeignKey(Expert, null=True, blank=True, default = None)
class Material(models.Model):
name = models.CharField(_('name'), max_length=50)
description = models.TextField(_('description'), blank=True)
slug = models.SlugField()
category = models.ForeignKey(Category, verbose_name=_('category'))
forms
class Demande_ExpertiseForm(forms.ModelForm):
class Meta:
model = Demande_Expertise
def __init__(self, *args, **kwargs):
super(Demande_ExpertiseForm, self).__init__(*args, **kwargs)
self.fields['material'].queryset = Material.objects.filter(category=Category)
no error but filtering don't work.
how to filter name of the model Category?
You can filter a relation in a queryset by a field by using double underscores (so category__name in this case) and passing in whatever you want to filter it by.
class Demande_ExpertiseForm(forms.ModelForm):
class Meta:
model = Demande_Expertise
def __init__(self, *args, **kwargs):
super(Demande_ExpertiseForm, self).__init__(*args, **kwargs)
self.fields['material'].queryset = Material.objects.filter(category__name="name to filter")
In this case it will filter all of the Material objects to those which have a Category set to exactly name to filter. You can learn more by reading the Django documentation on retrieving objects.