I have a module PartLog witch is used to generate a report from another modules like stock, part and user. I am also using message to store in report description fileds :- look
My PartLog Model:-
class PartLog(models.Model):
    ACTION_ADD = 'Added Part'
    ACTION_REMOVED = 'Removed Part'
    ACTION_DUPLICATED = 'Part Duplicated'
    ACTION_EDITED = 'Part Updated'
    ACTION_ADD_ORDER_TO_PART = 'Added Order to Part'
    ACTION_ADD_STOCK_TO_PART = 'Added %s items to stock'
    ACTION_REMOVE_FROM_STOCK = 'Removed %s items from stock'
    ACTION_CREATED_STOCK = 'Created Stock Item'
    ACTION_DELETED_STOCK = 'Removed Stock Item'
    ACTION_MOVED_TO = 'Stock item moved'
    ACTION_STOCK_EDITED = 'Stock Updated'
    ACTION_STOCK_DUPLICATED = 'Stock Duplicated'
    ACTION_ORDERED_PART = 'Part Ordered'
    ACTION_CHOICES = (
        (ACTION_ADD, ACTION_ADD),
        (ACTION_REMOVED, ACTION_REMOVED),
        (ACTION_DUPLICATED, ACTION_DUPLICATED),
        (ACTION_EDITED, ACTION_EDITED),
        (ACTION_ADD_ORDER_TO_PART, ACTION_ADD_ORDER_TO_PART),
        (ACTION_ADD_STOCK_TO_PART, ACTION_ADD_STOCK_TO_PART),
        (ACTION_REMOVE_FROM_STOCK, ACTION_REMOVE_FROM_STOCK),
        (ACTION_CREATED_STOCK, ACTION_CREATED_STOCK),
        (ACTION_DELETED_STOCK, ACTION_DELETED_STOCK),
        (ACTION_MOVED_TO, ACTION_MOVED_TO),
        (ACTION_STOCK_EDITED, ACTION_STOCK_EDITED),
        (ACTION_STOCK_DUPLICATED, ACTION_STOCK_DUPLICATED),
        (ACTION_ORDERED_PART, ACTION_ORDERED_PART),
    )
    part = models.ForeignKey(to=Part, on_delete=models.SET_NULL, null=True)
    transaction_time = models.DateTimeField('Transaction Time')
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    change_quantity = models.PositiveSmallIntegerField('Change Quantity')
    action = models.CharField(max_length=40, choices=ACTION_CHOICES)
    @property
    def message(self):
        if self.action in [self.ACTION_REMOVE_FROM_STOCK, self.ACTION_ADD_STOCK_TO_PART]:
            return self.action % self.change_quantity
        return self.action
    @staticmethod
    def log(part, user, change_quantity, action):
        PartLog.objects.create(part=part, user=user,
                               change_quantity=change_quantity,
                               action=action, transaction_time=datetime.now())
My Stock Item Create view:-
class StockItemCreate(PermissionRequiredMixin, AjaxCreateView):
    """
    View for creating a new StockItem
    Parameters can be pre-filled by passing query items:
    - part: The part of which the new StockItem is an instance
    - location: The location of the new StockItem
    If the parent part is a "tracked" part, provide an option to create uniquely serialized items
    rather than a bulk quantity of stock items
    """
    permission_required = ('users.add_stocks',)
    model = StockItem
    form_class = CreateStockItemForm
    context_object_name = 'item'
    ajax_template_name = 'modal_form.html'
    ajax_form_title = _('Create new Stock Item')
    def get_form(self):
        """ Get form for StockItem creation.
        Overrides the default get_form() method to intelligently limit
        ForeignKey choices based on other selections
        """
        form = super().get_form()
        # If the user has selected a Part, limit choices for SupplierPart
        if form['part'].value():
            part_id = form['part'].value()
            try:
                part = Part.objects.get(id=part_id)
                # Hide the 'part' field (as a valid part is selected)
                form.fields['part'].widget = HiddenInput()
                # trackable parts get special consideration
                if part.trackable:
                    form.fields['delete_on_deplete'].widget = HiddenInput()
                    form.fields['delete_on_deplete'].initial = False
                else:
                    form.fields.pop('serial_numbers')
                # If the part is NOT purchaseable, hide the supplier_part field
                if not part.purchaseable:
                    form.fields['supplier_part'].widget = HiddenInput()
                else:
                    # Pre-select the allowable SupplierPart options
                    parts = form.fields['supplier_part'].queryset
                    parts = parts.filter(part=part.id)
                    form.fields['supplier_part'].queryset = parts
                    # If there is one (and only one) supplier part available, pre-select it
                    all_parts = parts.all()
                    if len(all_parts) == 1:
                        # TODO - This does NOT work for some reason? Ref build.views.BuildItemCreate
                        form.fields['supplier_part'].initial = all_parts[0].id
            except Part.DoesNotExist:
                pass
        # Otherwise if the user has selected a SupplierPart, we know what Part they meant!
        elif form['supplier_part'].value() is not None:
            pass
        return form
    def get_initial(self):
        """ Provide initial data to create a new StockItem object
        """
        # Is the client attempting to copy an existing stock item?
        item_to_copy = self.request.GET.get('copy', None)
        if item_to_copy:
            try:
                original = StockItem.objects.get(pk=item_to_copy)
                initials = model_to_dict(original)
                self.ajax_form_title = _("Copy Stock Item")
            except StockItem.DoesNotExist:
                initials = super(StockItemCreate, self).get_initial().copy()
        else:
            initials = super(StockItemCreate, self).get_initial().copy()
        part_id = self.request.GET.get('part', None)
        loc_id = self.request.GET.get('location', None)
        # Part field has been specified
        if part_id:
            try:
                part = Part.objects.get(pk=part_id)
                initials['part'] = part
                initials['location'] = part.get_default_location()
                initials['supplier_part'] = part.default_supplier
            except Part.DoesNotExist:
                pass
        # Location has been specified
        if loc_id:
            try:
                initials['location'] = StockLocation.objects.get(pk=loc_id)
            except StockLocation.DoesNotExist:
                pass
        return initials
    def post(self, request, *args, **kwargs):
        """ Handle POST of StockItemCreate form.
        - Manage serial-number valdiation for tracked parts
        """
        form = self.get_form()
        data = {}
        valid = form.is_valid()
        if valid:
            part_id = form['part'].value()
            try:
                part = Part.objects.get(id=part_id)
                quantity = Decimal(form['quantity'].value())
            except (Part.DoesNotExist, ValueError, InvalidOperation):
                part = None
                quantity = 1
                valid = False
                form.errors['quantity'] = [_('Invalid quantity')]
            if part is None:
                form.errors['part'] = [_('Invalid part selection')]
            else:
                # A trackable part must provide serial numbesr
                if part.trackable:
                    sn = request.POST.get('serial_numbers', '')
                    sn = str(sn).strip()
                    # If user has specified a range of serial numbers
                    if len(sn) > 0:
                        try:
                            serials = ExtractSerialNumbers(sn, quantity)
                            existing = []
                            for serial in serials:
                                if not StockItem.check_serial_number(part, serial):
                                    existing.append(serial)
                            if len(existing) > 0:
                                exists = ",".join([str(x) for x in existing])
                                form.errors['serial_numbers'] = [_('The following serial numbers already exist: ({sn})'.format(sn=exists))]
                                valid = False
                            # At this point we have a list of serial numbers which we know are valid,
                            # and do not currently exist
                            form.clean()
                            data = form.cleaned_data
                            for serial in serials:
                                # Create a new stock item for each serial number
                                item = StockItem(
                                    part=part,
                                    quantity=1,
                                    serial=serial,
                                    supplier_part=data.get('supplier_part'),
                                    location=data.get('location'),
                                    batch=data.get('batch'),
                                    delete_on_deplete=False,
                                    status=data.get('status'),
                                    notes=data.get('notes'),
                                    URL=data.get('URL'),
                                )
                                item.save(user=request.user)
                        except ValidationError as e:
                            form.errors['serial_numbers'] = e.messages
                            valid = False
                else:
                    # For non-serialized items, simply save the form.
                    # We need to call _post_clean() here because it is prevented in the form implementation
                    form.clean()
                    form._post_clean()
                    item = form.save(commit=False)
                    item.save(user=request.user)
                    PartLog.log(
                        part=part, change_quantity=form.cleaned_data.get('quantity', 0),
                        action=PartLog.ACTION_ADD_STOCK_TO_PART, user=request.user
                    )
                    data['pk'] = item.pk
                    data['url'] = item.get_absolute_url()
                    data['success'] = _("Created new stock item")
        data['form_valid'] = valid
        return self.renderJsonResponse(request, form, data=data)
Need to show message in description like " Added %S items to stock with %S location "
Location is just we select at the time of Stock item creation.
