Re: Need help modifying form on intermediate page of admin action
I looked over those apps and I don't think they'll help with my issue. Let's say that Crate 1 has a capacity of 12 and currently holds 10 jars. If I look at the jars in Crate 2, select 3 of them, and then trigger the admin action to move the selected jars, Crate 1 should *not* be in the drop down list on the intermediate form because it only has room for 2 more jars. There isn't really a value entered by the user, it's just the number of jars that are selected before the admin action is triggered that matters. I do not know how to modify the value of dest in an unbound instance of MoveMultipleJarsForm based on the length of the queryset. As a workaround, I think I could do some validation in move_multiple_jars() that would check the capacity of the destination and generate an error message if the destination can't hold all the selected jars, but that seems inelegant. Jack. On Saturday, July 29, 2017 at 10:24:02 PM UTC-7, mark wrote: > > You might find one of these helpful - > > https://github.com/digi604/django-smart-selects > > https://github.com/yourlabs/django-autocomplete-light > > Basically, you want a "chained select" that is populated after a value is > entered by the user, if I understand the problem. If you want to roll your > own, then you need something like ajax or node.js to populate the crate > select once you know how many jars you want to ship. > > Another way to think about it, is to use a validation on the crate object > to make sure there is room. This solution may not be as elegant, but does > not need any additional coding outside of django. > > Good luck! > > Mark > > On Sat, Jul 29, 2017 at 8:57 PM, Jack Twilley > wrote: > >> I have a Django app which keeps inventory. There are two relevant >> classes here, one named Jar and another named Crate. The Jar class has an >> attribute crate which is a foreign key for the Crate class. The Crate >> class has an attribute capacity of type models.IntegerField which >> represents the maximum number of Jar objects that it can hold. The Crate >> class also has a property "jars" which returns "self.jar_set.filter( >> is_active=True).count()" or in other words, the number of Jar objects >> with is_active set to True that are associated with that Crate object. >> >> This code is from models.py and shows the two object classes: >> >> class Crate(models.Model): >> number = models.IntegerField() >> slug = models.SlugField(max_length=10, unique=True, blank=True) >> capacity = models.IntegerField(default=12) >> # bin where the crate can currently be found >> bin = models.ForeignKey(Bin) >> >> >> created_at = models.DateTimeField(auto_now_add=True) >> updated_at = models.DateTimeField(auto_now=True) >> >> >> class Meta: >> ordering = ['number'] >> >> >> @property >> def jars(self): >> return self.jar_set.filter(is_active=True).count() >> >> >> @property >> def shortname(self): >> return "C%d" % self.number >> >> >> @property >> def longname(self): >> return "Crate %d" % self.number >> >> >> @property >> def name(self): >> return self.longname >> >> >> def __str__(self): >> return self.name >> >> >> def save(self, *args, **kwargs): >> self.slug = 'c%d' % self.number >> super(Crate, self).save(*args, **kwargs) >> >> >> def get_absolute_url(self): >> return reverse('inventory_crate', kwargs={'crate_slug': self.slug >> }) >> >> >> def clean(self): >> # ensure that the current number of jars is less than or equal >> to the capacity >> if self.jars > self.capacity: >> raise ValidationError('Capacity of crate exceeded') >> >> >> >> >> class Jar(models.Model): >> product = models.ForeignKey(Product) >> number = models.IntegerField() >> slug = models.SlugField(max_length=13, unique=True, blank=True) >> # volume in liters >> volume = models.IntegerField(default=1) >> crate = models.ForeignKey(Crate) >> # is_active = not yet sold >> is_active = models.BooleanField(default=True) >> # is_available = considered 'in stock' >> is_available = models.BooleanField(default=True) >> created_at = models.DateTimeField(auto_now_add=True) >> updated_at = models.DateTimeField(auto_now=True) >> >> >> objects = models.Manager() >> instock = InStockJarManager() >> >> >> class Meta: >> ordering = ['created_at'] >> unique_together = ('product', 'number') >> >> >> @property >> def name(self): >> return "%s%d" % (self.product, self.number) >> >> >> def __str__(self): >> return self.name >> >> >> def save(self, *args, **kwargs): >> self.slug = ''.join([self.product.slug, str(self.number)]) >> super(Jar, self).save(*args, **kwargs) >> >> >> def get_absolute_url(self): >> return reverse('inventory_jar', kwargs={'jar_slug': self.slug}) >> >> >> I
Re: Need help modifying form on intermediate page of admin action
You might find one of these helpful - https://github.com/digi604/django-smart-selects https://github.com/yourlabs/django-autocomplete-light Basically, you want a "chained select" that is populated after a value is entered by the user, if I understand the problem. If you want to roll your own, then you need something like ajax or node.js to populate the crate select once you know how many jars you want to ship. Another way to think about it, is to use a validation on the crate object to make sure there is room. This solution may not be as elegant, but does not need any additional coding outside of django. Good luck! Mark On Sat, Jul 29, 2017 at 8:57 PM, Jack Twilley wrote: > I have a Django app which keeps inventory. There are two relevant classes > here, one named Jar and another named Crate. The Jar class has an > attribute crate which is a foreign key for the Crate class. The Crate > class has an attribute capacity of type models.IntegerField which > represents the maximum number of Jar objects that it can hold. The Crate > class also has a property "jars" which returns "self.jar_set.filter( > is_active=True).count()" or in other words, the number of Jar objects > with is_active set to True that are associated with that Crate object. > > This code is from models.py and shows the two object classes: > > class Crate(models.Model): > number = models.IntegerField() > slug = models.SlugField(max_length=10, unique=True, blank=True) > capacity = models.IntegerField(default=12) > # bin where the crate can currently be found > bin = models.ForeignKey(Bin) > > > created_at = models.DateTimeField(auto_now_add=True) > updated_at = models.DateTimeField(auto_now=True) > > > class Meta: > ordering = ['number'] > > > @property > def jars(self): > return self.jar_set.filter(is_active=True).count() > > > @property > def shortname(self): > return "C%d" % self.number > > > @property > def longname(self): > return "Crate %d" % self.number > > > @property > def name(self): > return self.longname > > > def __str__(self): > return self.name > > > def save(self, *args, **kwargs): > self.slug = 'c%d' % self.number > super(Crate, self).save(*args, **kwargs) > > > def get_absolute_url(self): > return reverse('inventory_crate', kwargs={'crate_slug': self.slug > }) > > > def clean(self): > # ensure that the current number of jars is less than or equal to > the capacity > if self.jars > self.capacity: > raise ValidationError('Capacity of crate exceeded') > > > > > class Jar(models.Model): > product = models.ForeignKey(Product) > number = models.IntegerField() > slug = models.SlugField(max_length=13, unique=True, blank=True) > # volume in liters > volume = models.IntegerField(default=1) > crate = models.ForeignKey(Crate) > # is_active = not yet sold > is_active = models.BooleanField(default=True) > # is_available = considered 'in stock' > is_available = models.BooleanField(default=True) > created_at = models.DateTimeField(auto_now_add=True) > updated_at = models.DateTimeField(auto_now=True) > > > objects = models.Manager() > instock = InStockJarManager() > > > class Meta: > ordering = ['created_at'] > unique_together = ('product', 'number') > > > @property > def name(self): > return "%s%d" % (self.product, self.number) > > > def __str__(self): > return self.name > > > def save(self, *args, **kwargs): > self.slug = ''.join([self.product.slug, str(self.number)]) > super(Jar, self).save(*args, **kwargs) > > > def get_absolute_url(self): > return reverse('inventory_jar', kwargs={'jar_slug': self.slug}) > > > I have written an admin action named "move_multiple_jars" on the JarAdmin > class which allows me to select multiple Jar objects and move them to a > particular Crate object. Right now, the intermediate page for that admin > action has a form "MoveMultipleJarsForm" with a drop down list which > contains all Crate objects sorted by number. This admin action works in > that it does move the Jar objects from one Crate object to another. I > would like that drop down list to contain only the Crate objects which have > sufficient extra capacity to hold the number of Jar objects selected. > > This code is from admin.py: > > class JarAdmin(SmarterModelAdmin): > valid_lookups = ('product',) > form = JarAdminForm > list_display = ('product', 'number', 'is_active', 'is_available', > 'crate',) > list_display_links = ('number',) > list_filter = ('product', 'crate', 'is_active') > list_per_page = 50 > ordering = ['-created_at', 'is_active'] > search_fields = ['product', 'crate'] > readonly_fields = ('created_at', 'updated_at',) > actions = ['move_multiple_jars'] > > > class MoveM
Need help modifying form on intermediate page of admin action
I have a Django app which keeps inventory. There are two relevant classes here, one named Jar and another named Crate. The Jar class has an attribute crate which is a foreign key for the Crate class. The Crate class has an attribute capacity of type models.IntegerField which represents the maximum number of Jar objects that it can hold. The Crate class also has a property "jars" which returns "self.jar_set.filter( is_active=True).count()" or in other words, the number of Jar objects with is_active set to True that are associated with that Crate object. This code is from models.py and shows the two object classes: class Crate(models.Model): number = models.IntegerField() slug = models.SlugField(max_length=10, unique=True, blank=True) capacity = models.IntegerField(default=12) # bin where the crate can currently be found bin = models.ForeignKey(Bin) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['number'] @property def jars(self): return self.jar_set.filter(is_active=True).count() @property def shortname(self): return "C%d" % self.number @property def longname(self): return "Crate %d" % self.number @property def name(self): return self.longname def __str__(self): return self.name def save(self, *args, **kwargs): self.slug = 'c%d' % self.number super(Crate, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('inventory_crate', kwargs={'crate_slug': self.slug}) def clean(self): # ensure that the current number of jars is less than or equal to the capacity if self.jars > self.capacity: raise ValidationError('Capacity of crate exceeded') class Jar(models.Model): product = models.ForeignKey(Product) number = models.IntegerField() slug = models.SlugField(max_length=13, unique=True, blank=True) # volume in liters volume = models.IntegerField(default=1) crate = models.ForeignKey(Crate) # is_active = not yet sold is_active = models.BooleanField(default=True) # is_available = considered 'in stock' is_available = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) objects = models.Manager() instock = InStockJarManager() class Meta: ordering = ['created_at'] unique_together = ('product', 'number') @property def name(self): return "%s%d" % (self.product, self.number) def __str__(self): return self.name def save(self, *args, **kwargs): self.slug = ''.join([self.product.slug, str(self.number)]) super(Jar, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('inventory_jar', kwargs={'jar_slug': self.slug}) I have written an admin action named "move_multiple_jars" on the JarAdmin class which allows me to select multiple Jar objects and move them to a particular Crate object. Right now, the intermediate page for that admin action has a form "MoveMultipleJarsForm" with a drop down list which contains all Crate objects sorted by number. This admin action works in that it does move the Jar objects from one Crate object to another. I would like that drop down list to contain only the Crate objects which have sufficient extra capacity to hold the number of Jar objects selected. This code is from admin.py: class JarAdmin(SmarterModelAdmin): valid_lookups = ('product',) form = JarAdminForm list_display = ('product', 'number', 'is_active', 'is_available', 'crate',) list_display_links = ('number',) list_filter = ('product', 'crate', 'is_active') list_per_page = 50 ordering = ['-created_at', 'is_active'] search_fields = ['product', 'crate'] readonly_fields = ('created_at', 'updated_at',) actions = ['move_multiple_jars'] class MoveMultipleJarsForm(forms.Form): # JMT: this needs to somehow be restricted to those crates that have room dest = forms.ModelChoiceField(queryset=Crate.objects.all().order_by( 'number')) def move_multiple_jars(self, request, queryset): form = None if 'apply' in request.POST: form = self.MoveMultipleJarsForm(request.POST) if form.is_valid(): dest = form.cleaned_data['dest'] count = 0 for jar in queryset: jar.crate = dest jar.save() count += 1 plural = '' if count != 1: plural = 's' self.message_user(request, "Successfully moved %d jar%s to %s" % (count, plural, dest)) return HttpResponseRedirect(request.get_full_path()) if not form