Edit multiselect field? - django

So I have a ManyToMany field in my model and Django admin renders it as a multiselect field. It works fine and I have no issues — except that I can't Edit it after creating a record.
I tried Del key, mouse right-click, nothing worked. Looks like I have to delete the record and create it again?
This is the field I want to edit. I want to remove one or two of the above items. I'm on Windows.

Well it looks like there's a simpler solution:
(Courtesy of Webdev Hints)
Here's my models:
class Technology(models.Model):
title = models.CharField(max_length=10)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = 'Technologies'
class Project(models.Model):
title = models.CharField(max_length=100)
description = HTMLField()
technology = models.ManyToManyField(Technology, related_name='projects')
image = models.ImageField(upload_to='projects/')
def __str__(self):
return self.title
And the solution is to add the following to the admin.py:
#admin.register(Technology)
class TechnologyAdmin(admin.ModelAdmin):
pass
class TechnologyInline(admin.TabularInline):
model = Project.technology.through
#admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
inlines = (TechnologyInline,)
exclude = ('technology',)
Now the ManyToMany filed is editable.

Related

Django multiple pictures one product

I have the following problem: I'm programming a webshop and every product has multiple pictures. So this is a one-to-many relation, where the foreign key is in the picture model. However, if i register the models "product" and "picture" to the admin site the user obviously needs to add a product then navigate to the pictures and add a picture and referencing a product within the picture creation process. Instead of this i want the user to be able to create a product and then add multiple pictures in the dropdown menu inside the same subpage inside admin-pannel. How can i accomplish this behaviour? It should look exact like it would with a many-to-many relation. But i don't want to use ManyToManyField sience i already tried it and then it lead to logical issues.
models.py:
class Picture(models.Model):
picture = models.ImageField(upload_to='shop/static/shop/images/')
product = models.ForeignKey(Product, on_delete=models.CASCADE)
def __str__(self):
return self.picture.url
class Product(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
admin.py
admin.site.register(Picture)
admin.site.register(Product)
models.py
class Picture(models.Model):
picture = models.ImageField(upload_to='shop/static/shop/images/')
def __str__(self):
return self.picture.url
class Product(models.Model):
name = models.CharField(max_length=200)
picture = models.ForeignKey(Picture, on_delete=models.CASCADE)
def __str__(self):
return self.name
admin.py
class PictureInline(modeladmin.StackedInline):
model = Picture
class ProductAdmin(admin.ModelAdmin):
inlines = [PictureInline]
admin.site.register(Product, ProductAdmin)
#NOTE: dont register you Picture model because you have put inline in product so from here you can directly put you pictures in the product.
class Picture(models.Model):
picture = models.ImageField(upload_to='shop/static/shop/images/')
def __str__(self):
return self.picture.url
class Product(models.Model):
name = models.CharField(max_length=200)
product = models.ManyToManyField(Picture, blank=True,related_name="product_img")
def __str__(self):
return self.name
Try using this instead.

Add new rows to related model on creation of parent model in Admin

I have models for adding products. The name of the products are in several languages, so I made a on-to-many raltion with a 'Name'-model.
This is my models
class Product(models.Model):
active = models.BooleanField()
class ProductName(models.Model):
productName = models.CharField(max_length=250)
product = models.ForeignKey('Product', on_delete=models.CASCADE)
language = models.ForeignKey('Language', on_delete=models.CASCADE)
def __str__(self):
return self.productName
class Language(models.Model):
language = models.CharField(max_length=55)
languageAbbreviation = models.CharField(max_length=10)
def __str__(self):
return self.language
Now in the admin page of mysite, I want to add product names on creation of a product.
I tried some misarable attempt with some thing I found about 'admin.TabularInline'. But I think that is wrong because nothing is working with that.
Any suggestion about how to solve this is much appreciated!
A model admin like this:
class ProductAdmin(admin.ModelAdmin):
class ProductNameInline(admin.TabularInline):
model = ProductNameInline
fields = ['productName', 'language']
model = Product
inlines = [ProductNameInline]
should provide you with a page that allows you set the name(s) of a product.
Make sure all the necessary static files for the javascript are available.

django-nested-inline missing fields when adding new inline row

In our project, i've been making use of the latest version of django-nested-inlines v0.3.7 with django 1.7
I have the following definition in my django admin to display the inlines
class SpecsGroupedContentInline(NestedStackedInline):
model = SpecificationGroupedContent
extra = 1
fk_name = "specification"
fields = ["field_unit"]
class SpecsContentInline(NestedStackedInline):
model = SpecificationListContent
extra = 1
fk_name = "specification"
fields = ["content"]
class SpecsInline(NestedStackedInline):
model = Specification
inlines = [SpecsContentInline, SpecsGroupedContentInline]
extra = 1
fk_name = "product"
class ProductAdmin(NestedModelAdmin):
inlines = [
SpecsInline
]
list_display = ('name', 'sku')
form = ProductAdminForm
When the page loads, the page looks like this
Initial product page load
It's a bit hard to see but the specs section has a title, an inline for Listed Contents and an inline for Grouped Contents. Afterwards, there's an empty Specs section with an empty title, empty Listed Contents, and empty Grouped Contents.
When I press the "Add another Specification" button at the bottom of the Specification inline to add a new row, the result of the new entry looks like this
New Specification entry image
As you can see, the Grouped Content field "Field Unit" is missing. I'm not sure if my setup is incorrect, but i found this stack overflow entry with a similar setup to mine
Django nested inlines not working?
It is for a different error though but we have a similar inline setup so i was thinking this setup is ok for django-nested-inlines.
Also, I'm sure if it's related but is django-nested-inlines affected if a nested inline model is a foreign key of another model? The SpecificationsGroupedContent model is a foreign key of another model unlike the SpecificationsListContent. I did a quick test where the SpecsInline inlines contained either SpecsGroupedContentInline only or SpecsContentInline only. It was working perfectly when using only SpecsContentInline but the error occurs when using SpecsGroupedContentInline.
For reference, here are the models I'm using with the related model for SpecsGroupedContent
class Product(AuthorStampedModel):
name = models.CharField(max_length=100)
sku = models.CharField(unique=True, max_length=100, verbose_name='SKU')
summary = models.TextField(blank=True, default="")
def __unicode__(self):
return self.return_product_details()
def return_product_details(self):
return '%s: %s' % (self.sku, self.name)
class Specification(models.Model):
product = models.ForeignKey('Product', related_name='specs')
title = models.CharField(max_length=100)
def __unicode__(self):
return self.return_spec_string()
def return_spec_string(self):
return '%s: %s' % (self.product.return_product_details(), self.title)
class SpecificationListContent(models.Model):
specification = models.ForeignKey('Specification', related_name='list_content')
content = models.CharField(max_length=255)
class Meta:
verbose_name_plural = 'Specification Listed Contents'
def __unicode__(self):
return self.specification.return_spec_string()
class SpecificationGroupedContent(models.Model):
specification = models.ForeignKey('Specification', related_name='group_content')
field_unit = models.CharField(max_length=255)
class Meta:
verbose_name_plural = 'Specification Grouped Contents'
def __unicode__(self):
return self.specification.return_spec_string()
class SpecificationGroupedContentValue(models.Model):
specification_grouped_content = models.ForeignKey(
'SpecificationGroupedContent',
related_name='group_content_value'
)
value = models.CharField(max_length=255)
class Meta:
verbose_name_plural = 'Specification Grouped Content Values'
def __unicode__(self):
return self.specification_grouped_content.specification.return_spec_string()
Thanks

Django FilteredSelectMultiple with a massive amount of data

I have the following models:
class Student(models.Model):
class Meta:
app_label = 'ground'
name = models.CharField(max_length=255)
def __unicode__(self):
return unicode(self.name)
class Program(models.Model):
class Meta:
app_label = 'ground'
name = models.CharField(max_length=255)
student = models.ManyToManyField(Student)
def __unicode__(self):
return unicode(self.name)
And the following admin:
class ProgramAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {
'widget': admin.widgets.FilteredSelectMultiple(
Student._meta.verbose_name_plural, False)
}
}
admin.site.register(Program, ProgramAdmin)
As you can see I use django's FilteredSelectMultiple to display a nice select field for the Program admin where I can select multiple students at once.
Problem
I have over 2500 students in the database. The browser has problems with rendering all students into the select field. Is there a way to overcome this problem. Like doing stuff with javascript
It's not a browser problem. Django is fetching a list of data of all the students on every single load. If you keep it that way, it will be slow and slower. You can check out raw_id_fields.
I'm currently writing my own autocomplete widget... Stay tuned!

Django self-referential model as a many-to-many inline tree in the admin site

Suppose I have the following models in models.py:
class Category(models.Model):
name = models.CharField(max_length=128)
parent = models.ForeignKey('self', null=True, blank=True)
class Item(models.Model):
name = models.CharField(max_length=128)
categories = models.ManyToManyField(Category, related_name='categories')
class Membership(models.Model):
category = models.ForeignKey(Category)
item = models.ForeignKey(Item)
date_assigned = models.DateField()
And, as documented in Working with many-to-many intermediary models, I have this in admin.py:
class MembershipInline(admin.TabularInline):
model = Membership
extra = 3
class CategoryAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
class ItemAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
When creating an Item in the admin site, category inline forms are indeed rendered, but as mere <select> widgets, which is somewhat cumbersome, as each category is shown at the same level.
How could I get these rendered as trees? I don't need something very fancy and some indentation within the select would be just fine.
I tried with django-mptt and django-treebeard, but they don't seem to have the inline intermediary many-to-many model case covered.
If you register the Item model with mptt. You can overwrite the unicode method:
class Item(models.Model):
...
def __unicode__(self):
return '%s%s' % (' ' * self.level, super(MarkerCategory, self).__unicode__())
If you want a cleaner solution, you should overwrite the form, and change the widget and to do this logic in this specific widget.
I hate when browsers are "smart".
from django.utils.safestring import mark_safe
...
class Item(models.Model):
...
def __unicode__(self):
return mark_safe('%s%s' % (' ' * 4 * self.level,
super(Item, self).__unicode__()))
But I recomend that this logic is in a specify widget