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