I have manytomanyfield inside my model.The manytomanyfield field lists the products in the products table.
I want to enter the amount for each product I choose. How can I relate manytomanyfield to floatfield field?
That's my model:
`
class TaskSources(models.Model):
id = models.AutoField(primary_key=True)
user_task_id = models.ForeignKey(UserTask,on_delete=models.CASCADE)
product_id = models.ManyToManyField(Product, verbose_name="Product",default=None)
product_amount = models.FloatField(max_length=255,verbose_name="Product Amount")
`
The form:
`
class TaskSourcesForm(forms.ModelForm):
class Meta:
model = TaskSources
fields = ['product_id', 'product_amount']
`
The views:
`
#login_required(login_url="login")
def addUserTask(request):
user_task_form = UserTaskForm(request.POST or None,initial={'user_id': request.user})
task_sources_form = TaskSourcesForm(request.POST or None)
if request.method == 'POST':
if user_task_form.is_valid():
user_task = user_task_form.save(commit=False)
user_task.author = request.user
user_task.save()
print(user_task.id)
if task_sources_form.is_valid():
task_sources = task_sources_form.save(commit=False)
task_sources.user_task_id = UserTask(id = user_task.id)
task_sources.save()
task_sources_form.save_m2m()
messages.success(request,"Task added successfully!")
return redirect(".")
context = {
"user_task_form" : user_task_form,
"task_sources_form" : task_sources_form,
}
return render(request,"user/addtask.html",context)
`
Thanks for care.
I tried associating the two fields with each other, but I could not succeed.
If I got it right I think that what you need is an intermediate table between your models. That way you can link an amount of a product to a TaskSource, something similar to this:
class Product(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class ProductAmount(models.Model):
amount = models.FloatField(max_length=255,verbose_name="Product Amount")
product = models.ManyToManyField(Product, through='TaskSources')
def __str__(self):
return self.name
class UserTask(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class TaskSources(models.Model):
id = models.AutoField(primary_key=True) # this is not really necessary
task = models.ForeignKey(UserTask,on_delete=models.CASCADE)
product_amount = models.ForeignKey(ProductAmount, on_delete=models.CASCADE)
Related
I am new to Django. My query is
I store some quantity of components in a table. I want to sum the quantity sorting it by components and then use the summed quantity in some other table to do further calculations. How can I achieve this..
#views.py
class PurchaseCreateView(CreateView):
model = Purchase
fields = '__all__'
success_url = reverse_lazy("purchase_form")
def get_context_data(self,**kwargs):
context = super().get_context_data(**kwargs)
context['purchases'] = Purchase.objects.all()
return context
#models.py
class Purchase(models.Model):
purchase_date = models.DateField()
invoice_no = models.CharField(max_length=200,unique=True)
supplier =models.ForeignKey(Supplier,on_delete=models.CASCADE)
components = models.ForeignKey(Components,on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
remarks = models.TextField(max_length=500,blank=True,null=True)
def __str__(self):
return str(self.pk)
# Below is the Model where I want to use the summed quantity for further calc
class IntermediateStage(models.Model):
producttype = models.ForeignKey(ProductType,on_delete=models.CASCADE)
components = models.ForeignKey(Components,on_delete=models.CASCADE)
processingstage = models.ForeignKey(ProcessingStage,on_delete=models.CASCADE)
unitsrequired = models.PositiveIntegerField()
quantity = models.PositiveIntegerField(blank = True)**#want to store summed qty here**
total_quantity = models.IntegerField(blank= True)
class Meta:
unique_together = [['producttype','components','processingstage']]
def __str__(self):
return str(self.id)
#Components Model
class Components(models.Model):
name = models.CharField(max_length=100,unique=True)
producttype = models.ManyToManyField(ProductType, through='IntermediateStage')
def __str__(self):
return self.name
How can I pass the foreign key values from my model to my serialised json object?
Now I have this three models,
class Fleet(models.Model):
fleet_id = models.IntegerField('Id flota', primary_key=True, unique=True)
fleet_name = models.CharField('Nombre flota', max_length=20, unique=True)
def __str__(self):
return self.fleet_name + ' ' + str(self.fleet_id)
class Device(models.Model):
dev_eui = models.CharField(max_length=16, primary_key=True, unique=True)
producer = models.CharField(max_length=20)
model = models.CharField(max_length=20)
dev_name = models.CharField(max_length=20, unique=True)
fleet_id = models.ForeignKey(Fleet, on_delete=models.CASCADE)
def __str__(self):
return self.dev_eui
class DevData(models.Model):
data_uuid = models.UUIDField(primary_key=True, default=uuid.uuid1, editable=False)
frequency = models.IntegerField()
data_1 = models.FloatField()
data_2 = models.FloatField(null=True, blank=True)
dev_eui = models.ForeignKey(Device, on_delete=models.CASCADE) #hay que saber porque añade _id
def __str__(self):
return self.dev_eui
And what I'm doing is call my view function in my JS code to obtain some data like this.
def getData(request):
ctx = {}
if request.method == 'POST':
select = int(request.POST['Select'])
data = DevData.objects.order_by('dev_eui','-data_timestamp').distinct('dev_eui')
nodes = Device.objects.all()
fleets = Fleet.objects.all()
data = loads(serializers.serialize('json', data))
nodes = loads(serializers.serialize('json', nodes))
fleets = loads(serializers.serialize('json', fleets))
ctx = {'Data':data, 'Nodes':nodes, 'Fleets':fleets}
return JsonResponse(ctx)
And inside my js file I filter it with some if else conditionals.
This works well, but I'm sure I can do it directly in my view but I don't know how. How can I obtain just one JSON object with the three models information combined?
Thank you very much!!
You can write a custom serializer like this:
from django.core.serializers.json import Serializer
class CustomSerializer(Serializer):
def end_object(self, obj):
for field in self.selected_fields:
if field == 'pk':
continue
elif field in self._current.keys():
continue
else:
try:
if '__' in field:
fields = field.split('__')
value = obj
for f in fields:
value = getattr(value, f)
if value != obj and isinstance(value, JSON_ALLOWED_OBJECTS) or value == None:
self._current[field] = value
except AttributeError:
pass
super(CustomSerializer, self).end_object(obj)
Then use it like this
serializers = CustomSerializer()
queryset = DevData.objects.all()
data = serializers.serialize(queryset, fields=('data_uuid', 'dev_eui__dev_eui', 'dev_eui__fleet_id__fleet_name'))
I have wrote an article regarding serializing nested data here. You can check that out as well.
I have two models ItemCategory and Item, I want to filter the list of ItemCategory by filtering is_published field of item.
class ItemCategory(models.Model):
category_name = models.CharField(max_length=50, unique=True)
category_image = models.ImageField(upload_to='item-category', null=True)
def __str__(self):
return 'category: ' + self.category_name
class Item(models.Model):
item_name = models.CharField(max_length=50)
item_desc = models.CharField(max_length=500, blank=True)
price = models.FloatField()
item_image = models.ImageField(upload_to='item-images')
num_of_items_available = models.IntegerField()
category_name = models.ForeignKey(ItemCategory, on_delete=models.CASCADE, null=True, related_name='items')
is_published = models.BooleanField(default=False)
def __str__(self):
return 'item: ' + self.item_name
Here is my approach but didn't get any success.
class ItemCategoryView(viewsets.ViewSet):
permission_classes = (AllowAny,)
serializer_class = ItemCategoryListSerializer
def list(self, request, format=None):
queryset = ItemCategory.objects.filter(items__in=Item.objects.filter(is_published=True))
serializer = ItemCategorySerializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
ItemCategorySerializer looks like this
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('pk', 'item_name', 'item_desc', 'price', 'item_image', 'num_of_items_available',
'category_name', 'is_published')
class ItemCategorySerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True, read_only=True)
class Meta:
model = ItemCategory
fields = ('pk', 'category_name', 'category_image', 'items')
Can anyone tell my how i can approach to this problem?
Edit
I have tried this two queries
queryset = ItemCategory.objects.filter(items__in=Item.objects.filter(is_published=True)) queryset = ItemCategory.objects.filter(items__is_published=True)
I think both this query work but not in the way i want. Heres how it works now.
It returns list of ItemCategory where any list of item with is_published = True. Say There are 3 categories(A, B , C) and each category has 3 list of item (A1, A2, A3, B1, B2, B3, C1, C2, C3). and let all have is_published = False except C3.
So now the query result is something like this. It returns only C Category with all the list item C1, C2, C3. which is not the desired result. I should be getting only C3 since this is the only published Item.
You can achieve this with filter and prefetch_related:
queryset = ItemCategory.objects.filter(items__is_published=True).prefetch_related(Prefetch("items", queryset=Item.objects.fiter(is_published=True))
I think you need to filter them items before return the the category itself.
Filter all published items.
Filter all categories by published items.
Maybe you can use this method, but previously I suggest you to use the QuerySet manager.
1. models.py
class ItemCategory(models.Model):
category_name = models.CharField(max_length=50, unique=True)
category_image = models.ImageField(upload_to='item-category', null=True)
def get_published_items(self):
"""
return all items contains with this single Category.
"""
return Item.objects.published().filter(category_name__pk=self.pk)
def __str__(self):
return 'category: ' + self.category_name
class ItemQuerySet(models.QuerySet):
def published(self):
return self.filter(is_published=True)
def unpublished(self):
return self.filter(is_published=False)
class Item(models.Model):
....
category_name = models.ForeignKey(
ItemCategory, on_delete=models.CASCADE,
null=True, related_name='items')
is_published = models.BooleanField(default=False)
objects = ItemQuerySet.as_manager()
def __str__(self):
return 'item: ' + self.item_name
2. views.py
class ItemCategoryView(viewsets.ViewSet):
permission_classes = (AllowAny,)
serializer_class = ItemCategoryListSerializer
def list(self, request, format=None):
# find all categories first
published_categories_by_items = [ c.category_name for c in Item.objects.published() ]
# then, filter the categories itself.
queryset = ItemCategory.objects.filter(pk__in=[ c.pk for c in published_categories_by_items]).distinct()
serializer = ItemCategorySerializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Have a models:
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
variation_1 = models.BooleanField(default=True)
variation_2 = models.BooleanField(default=True)
variation_3 = models.BooleanField(default=True)
class Order(models.Model):
buyer = models.ForeignKey(User, related_name='buyer')
product = models.ForeignKey(Product)
variations_select = models.CharField(max_length=50, choices=VARIATIONS)
in forms.py
class OrderForm(forms.ModelForm):
variations_select = forms.ChoiceField(choices=VARIATIONS)
class Meta:
model = Order
fields = [
'variations_select'
]
i need to create a clean function that will check if variation_1 or variation_2 or variation_3 are availiable in Product. For this a need request Product.id to def clean_variations_select(self): How to do this?
def clean_variations_select(self):
product = Product.object.get(id = product.id)
variations_select = self.cleaned_data.get("variations_select")
if variations_select == "Variation_1" and product.variation_1 == False:
raise forms.ValidationError("variation_1 was sold already")
else:
return variations_select
product = Product.object.get(id = product.id) - don't work cause Order isn't created to database yet(but in rendering view link to new order creation i have that ../product.id/new_order).
You need to define an __init__ method for your class which should accept your product id as an argument.
def __init__(self,*args,**kwargs):
self.product_id = kwargs.pop('product_id')
super(OrderForm,self).__init__(*args,**kwargs)
When you initialize your form, you pass your product_id as a keyword argument.
OrderForm(request.POST, product_id=product_id)
And in clean method you can use self.product_id to get the Product object you want.
def clean_variations_select(self):
product = Product.object.get(id=self.product_id)
variations_select = self.cleaned_data.get("variations_select")
if variations_select == "Variation_1" and product.variation_1 == False:
raise forms.ValidationError("variation_1 was sold already")
else:
return variations_select
I have a model that looks like this
class RSVP (models.Model):
def __unicode__(self):
return self.firstName + " " + self.lastName
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=30)
rsvpID = models.CharField(max_length=9, unique = True)
allowedAdults = models.IntegerField(default = 2)
allowedChildren = models.IntegerField(default = 0)
adultsAttending = models.IntegerField(default = 0)
childrenAttending = models.IntegerField(default = 0)
and I have a ModelForm that looks like this
class RsvpForm(ModelForm):
class Meta:
model = RSVP
exclude= ('firstName', 'lastName', 'allowedAdults', 'allowedChildren')
What I would like to happen is that instead of a text field for the adultsAttending, a dropdown box with the values 0 to allowedAdults shows up. This is for a wedding rsvp site and I'd like to set the max number of +1's an invitee can bring on an individual basis
Any thoughts on how to go about this?
I'm thinking you want to fork the allowed children/ adults as well as the name to another model:
models.py
class Invited(models.Model):
f_name = models.CharField()
l_name = models.CharField()
allowed_adults = models.IntegerField()
allowed_children = models.IntegerField()
class RSVP(models.Model):
invited = models.ForeignKey(Invited)
adults_attending = models.IntegerField()
children_attending = models.IntegerField()
Then you would create the invited objects and assign the allowed adults and children. And the RSVP form would take those number into account when generating the choices for your drop down box.
The drop down can be implemented by overriding the IntegerField widget with a ChoiceField
forms.py
class InvitedForm(forms.ModelForm):
class Meta:
model = Invited
class RSVPForm(forms.ModelForm):
class Meta:
model = RSVP
exclude = ['invited',]
def __init__(self, *args, **kwargs):
max_adults = kwargs.pop('max_adults',2) #default to 2 if no max set
max_children = kwargs.pop('max_children',2) #default to 2 if no max set
super(RSVPForm, self).__init__(*args, **kwargs)
adult_choices = ( (x,str(x)) for x in range(max_adults+1)) )
children_choices = ( (x,str(x)) for x in range(max_children+1)) )
self.fields['adults_attending'] = forms.ChoiceField(choices = adult_choices)
self.fields['children_attending'] = forms.ChoiceField(choices = children_choices)
views.py
def rsvp_view(request, invited_id):
invited = get_object_or_404(Invited, pk=invited_id)
if request.method=='POST':
form = RSVPForm(request.POST, max_adults=invited.allowed_adults,
max_children=invited.allowed_children)
if form.is_valid():
rsvp = form.save(commit=False)
rsvp.invited = invited
rsvp.save()
return HttpResponse("Success")
else:
form = RSVPForm(max_adults=invited.allowed_adults, max_children=invited.allowed_children)
context = { 'form':form,
'invited':invited }
return render_to_response('rsvp.html', context,
context_instance=RequestContext(request))