I feel like I've exhausted my google-fu on this subject. I've tried so many different ways, I can't remember what I've tried.
I have a class "Recipe" which has 3 many_to_many fields. I've got an empty form using formsets for each many_to_many object for new.
I'm now modifying the form to include "update", but I cannot seem to get the formsets to populate the data. I've tried "instance=", I've tried passing in a dictionary "model_to_dict", but I can't seem to figure this out. My current iteration looks like this:
models.py:
class Recipe(models.Model):
def __str__(self):
return self.name
class Meta:
unique_together = ('name', 'version')
bs_file = models.FileField(storage=fs,null=True)
name = models.CharField(max_length=75)
dateCreated = models.DateField()
dateUpdated = models.DateField(null=True, blank=True)
version = models.IntegerField(null=True, blank=True)
#type = models.CharField(max_length=30) #Cider, Mead, Wine, etc
category = models.ForeignKey(BatchCategory,on_delete=models.CASCADE)
brewer = models.CharField(max_length=30, null=True)
batchSize = models.FloatField() #in Liters
source = models.CharField(max_length=50, null=True) #Where did the recipe come from
pairing = models.CharField(max_length=250, null=True) # Textfield listing various foods. TODO: Refactor
notes = models.TextField()
estOG = models.FloatField()
estFG = models.FloatField()
estABV = models.FloatField()
fermentables = models.ManyToManyField(RecipeFermentable)
adjuncts = models.ManyToManyField(RecipeAdjunct)
yeasts = models.ManyToManyField(RecipeYeasts)
You can see my 3 many_to_many fields at the bottom as "fermentables", "adjuncts", and "yeasts".
In Views, after I check if I have a 'pk', I try to assign the data to the formsets (i.e. fermentable_set, adjunct_set, yeast_set) using Model.objects.all()
views.py:
def addRecipe(request,pk=None):
if request.method == "GET":
form = RecipeAddForm()
fermentable_set = formset_factory(FermentableForm)
adjunct_set = formset_factory(AdjunctForm)
yeast_set = formset_factory(YeastForm)
if pk:
# We have a recipe to edit. Load it up
recipe = Recipe.objects.get(pk=pk)
form = RecipeAddForm(initial=model_to_dict(recipe))
fermentable_set = fermentable_set(recipe.fermentables.all().values(),prefix="ferm")
adjunct_set = adjunct_set(recipe.adjuncts.all().values(), prefix="adj")
yeast_set = yeast_set(recipe.yeasts.all().values(), prefix="yeast")
context = {'form': form, 'fermentable_set': fermentable_set,
'adjunct_set': adjunct_set,
'yeast_set': yeast_set}
return render(request, 'batchthis/addRecipe.html', context)
else:
form = RecipeAddForm(request.POST)
fermentable_set = formset_factory(FermentableForm)
if form.is_valid() and fermentable_set.is_valid():
recipe = Recipe()
data = form.cleaned_data
recipe.name = data['recipe_name']
recipe.dateCreated = data['date_created']
recipe.dateUpdated = data['date_updated']
recipe.brewer = data['brewer']
recipe.batchSize = data['batch_size']
recipe.notes = data['notes']
recipe.estOG = data['estOG']
recipe.estFG = data['estFG']
recipe.estABV = data['estABV']
category = BatchCategory.objects.get(pk=data['category'])
recipe.category = category
recipe.save()
#TODO Add Fermentable Formset
fermentables = []
adjuncts = []
yeasts = []
for form_item in fermentable_set:
fermentable = RecipeFermentable()
fermentable.amount = form_item.cleaned_data.get('amount_metric')
fermentable.fermentable = form_item.cleaned_data.get('fermentable')
fermentable.intended_use = form_item.cleaned_data.get('intended_use')
fermentable.is_fermentable = form_item.cleaned_data.get('is_fermentable')
fermentable.save()
fermentables.append(fermentable)
#TODO Add Adjuncts Formset
#TODO Add Yeasts Formset
recipe.fermentables.set(fermentables)
print("Returning response using Recipe PK of " + str(recipe.pk))
return HttpResponseRedirect(reverse('recipe', kwargs={'pk': recipe.pk}))
else:
return render(request, 'batchthis/addRecipe.html', {'form': form})
In order to be brief, I will give a snippet of my template.
addRecipe.html:
<div class = "col-md-6 col-mb-0">
{{ form.notes|as_crispy_field }}
</div>
</div>
{{ fermentable_set.management_form }}
<div id="fermentable_form_set">
{% for fermentable_form in fermentable_set %}
<div id="fermentable_form" class = "form-group row border-left-primary">
<div class = "col-md-4 col-mb-0">
{{ fermentable_form.fermentable|as_crispy_field }}
</div>
<div class = "col-md-2 col-mb-0">
{{ fermentable_form.amount_metric|as_crispy_field }}
</div>
<div class = "col-md-2 col-mb-0">
{{ fermentable_form.amount_unit|as_crispy_field }}
</div>
<div class = "col-md-2 col-mb-0">
{{ fermentable_form.intended_use|as_crispy_field }}
</div>
<div class = "col-md-2 col-mb-0">
{{ fermentable_form.is_fermentable|as_crispy_field }}
</div>
</div>
{% endfor %}
</div>
<input type="button" class="btn btn-secondary" value = "Add Fermentable" id="addFermentableFormButton">
{{ adjunct_set.management_form }}
<div id="adjunct_form_set">
{% for adjunct_form in adjunct_set %}
<div id="adjunct_form" class = "form-group row border-left-success">
<div class = "col-md-4 col-mb-0">
{{ adjunct_form.adjunct|as_crispy_field }}
</div>
My current iteration is complaining about my {{ fermentable_set.managementform }}.
too many values to unpack (expected 2)
This may be an open ended question, but my goal is to populate my formsets with the many_to_many objects assigned to Recipe. Any thoughts? Thanks in advance!
Related
I am trying to get a specific category products by category slug.I have Color model,Product model and product variation model in shop app.
class Colour(models.Model):
title = models.CharField(max_length=100)
color_code = models.CharField(max_length=50,null=True)
class Product(models.Model):
product_name = models.CharField(max_length=100,unique=True)
slug = models.SlugField(max_length=100,unique=True)
content = RichTextUploadingField()
price = models.IntegerField()
images = models.ImageField(upload_to='photos/products')
is_available = models.BooleanField(default=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE,related_name="procat")
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
is_featured = models.BooleanField()
class ProductVaraiant(models.Model):
product = models.ForeignKey(Product,on_delete=models.CASCADE)
color = models.ForeignKey(Colour,on_delete=models.CASCADE,blank=True, null=True)
size = models.ForeignKey(Size, on_delete=models.CASCADE,blank=True, null=True)
brand = models.ForeignKey(Brand,on_delete=models.CASCADE,blank=True, null=True)
amount_in_stock = models.IntegerField()
class Meta:
constraints = [
models.UniqueConstraint(
fields=['product', 'color', 'size','brand'],
name='unique_prod_color_size_combo'
In my views.py,
def shop(request,category_slug=None):
categories = None
products = None
if category_slug != None:
categories = get_object_or_404(Category,slug = category_slug)
products = Product.objects.filter(category=categories,is_available=True).order_by('id')
variation = ProductVaraiant.objects.filter(product__category = categories)
print(variation)
# color = color.objects.all()
products_count = products.count()
else:
products = Product.objects.all().filter(is_available=True).order_by('id')
products_count = products.count()
variation = ProductVaraiant.objects.all()
print(variation)
context = {
'products' : products,
'products_count' : products_count,
'variation' : variation
}
return render(request,'shop/shop.html',context)
my category model,
class Category(MPTTModel):
parent = TreeForeignKey('self',blank=True,null=True,related_name='children',on_delete=models.CASCADE)
category_name = models.CharField(max_length=200,unique=True)
category_img = models.ImageField(upload_to='photos/categories',blank=True)
slug = models.SlugField(max_length=100,unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def img_preview(self):
return mark_safe('<img src = "{url}" width = "50" height = "50"/>'.format(
url = self.category_img.url
))
def __str__(self):
return self.category_name
class Meta:
verbose_name_plural = 'categories'
class MPTTMeta:
order_insertion_by = ['category_name']
what i am trying to get is like i have 3 child category..Each category will have product of any color.So,if i filter product by category,color will be shown in sidebar of that category products without avoid getting duplicates as many product may have same color.So,i am getting same color multiple times.If i need to use distinct(),how to use it in query that will remove duplicate color based on product category.I tried this in template
<form>
<div class="custom-control custom-checkbox d-flex align-items-center justify-content-between mb-3">
<input type="checkbox" class="custom-control-input" checked id="color-all">
<label class="custom-control-label" for="price-all">All Color</label>
<span class="badge border font-weight-normal">1000</span>
</div>
{% for i in variation %}
{% ifchanged i.color %}
<div class="custom-control custom-checkbox d-flex align-items-center justify-content-between mb-3">
<input type="checkbox" class="custom-control-input filter-checkbox" id="{{i.color.id}}" data-filter="color">
<label class="custom-control-label" for="{{i.color.id}}">{{i.color}}</label>
<span class="badge border font-weight-normal">150</span>
</div>
{% endifchanged %}
{% endfor %}
</form>
But,it just remove duplicate of last iteration.How to avoid getting duplicates for all color?
Just where you have a line
# color = color.objects.all()
change it to color = variation.color.all().distinct('id') and then pass it to your template.
Answer of my problem,
what i did:
variation = ProductVaraiant.objects.filter(product__category = categories)
what i changed:
variation = ProductVaraiant.objects.filter(product__category=categories).values('color__title').distinct()
if using postgre database,don't need to use values,just use distinct('color') and you will need to use values for default database to avoid error below,
DISTINCT ON fields is not supported by this database backend
I am a beginner and learning django, here i want to let the user to select items multiple times in a m2m field, for example here i have a icecream model with flavor class linked to it in a m2m rel, when the form is displayed in the template i want user to select 1 option many times.
my models:
class IceCream(models.Model):
hold_choice = (
('Cone', 'Cone'),
('Cup','Cup'),
)
type_name = models.ForeignKey('IceCreamType', on_delete=models.CASCADE, null=True, blank=True)
flavor = models.ManyToManyField(Flavor, verbose_name='total scopes')
toppings = models.ManyToManyField(Topping)
holder = models.CharField(max_length=4, choices=hold_choice, default='Cone')
number_of_icecreams = models.PositiveIntegerField(default=1)
def __str__(self):
return str(self.type_name)
#property
def total_scope(self):
return self.flavor_set.all().count()
the flavor model has some options:
class Flavor(models.Model):
CHOCOLATE = 'Chocolate'
VANILLA = 'Vanilla'
STRAWBERRY = 'Strawberry'
WALLNUT = 'Wallnut'
KULFA = 'Kulfa'
TUTYFRUITY = 'Tuttyfruity'
choices = (
(CHOCOLATE, 'chocolate scope'),
(VANILLA, 'vanilla scope'),
(STRAWBERRY, 'strawberry scope'),
(WALLNUT, 'wallnut scope'),
(KULFA, 'kulfa scope'),
(TUTYFRUITY, 'tutyfruity scope'),
)
flavor = models.CharField(max_length=20, choices=choices, null=True)
def __str__(self):
return self.flavor
now if i display the form for it, how could it be possible for user to select 1 item(or scopes) many times, and also the method i've created in IceCream model doesnt work and gives the error IceCream has no attribute flavor_set.
the view for it to display
class OrderIceCream(CreateView):
model = IceCream()
template_name = 'prac/home.html'
fields = '__all__'
template:
<h1 class="text-center mt-5">Order Ice Cream</h1>
<div class="container border-dark">
<form action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" class="btn btn-primary mb-3 mt-3">
</form>
</div>
url is:
urlpatterns = [
path('home/<str:pk>/', IceCream.as_view(), name='home'),
path('order/<str:pk>/', OrderIceCream.as_view(), name='order-icecream'),
]
form on site image
I have a model called 'Competicion', with some objects and another model called 'Participante'. This second model has two fields: a foreignkey with the user and another foreingkey to 'Competicion'.
In the view, I've made queryset from 'Competicion' and with a for loop in the template I've given each object the button of the form.
With storing the user of the current session I have no problem but I want the form to know which object of the queryset it is to grab its id. #I have no problem with choices I just don't include them to save space
Models.py
class Competicion(models.Model):
ciudad = models.CharField(max_length=50, null=True, choices=Ciudades_a_elegir, default="Ninguna")
nombre = models.CharField(max_length=20, null=True, choices=Competiciones_a_elegir, default="Ninguna")
titulo = models.CharField(max_length=40, null=True)
fecha = models.DateField(null=True)
participantes = models.IntegerField(null=True)
flyer = models.ImageField(null=True, upload_to='imagenes', default='Ninguna')
def __str__(self):
return self.nombre + " " + self.titulo
class Participante(models.Model):
competicion = models.ForeignKey(Competicion, on_delete=models.CASCADE, null=True, blank=True)
participantes = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.competicion.nombre + " " + self.competicion.titulo
forms.py
class ParticipanteForm(ModelForm):
class Meta:
model = Participante
exclude = ['competicion', 'participantes']
views.py
def competiciones(request):
qs = Competicion.objects.all()
form = ParticipanteForm(request.POST or None)
if form.is_valid():
nombres = form.save()
nombres.competicion = ???#Help me
nombres.participantes = request.user
nombres.save()
return redirect('home')
context = {
'object_list':qs,
'form':form,
}
return render(request, "competiciones.html", context)
template
{% for i in object_list %}
<ul>
<li>{{i.nombre}}</li>
<li>{{i.ciudad}}</li>
<li>{{i.titulo}}</li>
<li>{{i.fecha}}</li>
<li>{{i.participantes}}</li>
{% if i.flyer %}
<img src="{{i.flyer.url}}" width="100px" >
{% endif %}
<li><form action="" method="POST">
{% csrf_token %}
<p> {{ form.competicion}} </p>
<p>{{form.participantes}}</p>
<input type="submit" name="Inscribirse" value="Inscribirse">
</form> </li>
</ul>
{% endfor %}
This is only like 1 course. In number one there is the different fields of the Competicion Model. And number two is the button of the form to the Participante Model, which fields are hidden and take the id of the course and the user. So I have a lot of these both courses displayed in the web. The function of the Particpante Model is to store the people who register in the course and the course itself.
def competiciones(request):
qs = Competicion.objects.all()
form = ParticipanteForm(request.POST or None)
if form.is_valid():
data = form.save()
data.participantes_id = request.user
for i in qs:
data.competicion_id = i.id
data.save()
return redirect('home')
I've already read many other threads complaining about this error message but I still can't figure this out. I try removing the fields that give the error, and the error message just moves to another field the next time I try to submit. They are CharField, Foreign Key, and other types.
forms.py
class TemporaryresponseForm(forms.ModelForm):
gender_custom = forms.CharField(
required=False,
label="",
)
ethnicity = forms.ModelChoiceField(
queryset=Ethnicity.objects.all(),
widget=forms.RadioSelect(),
empty_label=None,
required=True,
label="Which of the following best describes your ethnicity?"
)
...
class Meta:
model = Temporaryresponse
fields = [...'gender_custom', 'ethnicity',...]
views.py
def tr(request):
if request.method == "POST":
form = TemporaryresponseForm(request.POST)
if form.is_valid():
tempresponse = form.save(commit=False)
tempresponse.ip = "123456"
tempresponse.save()
return redirect('politicalpollingapp/index.html')
else:
form = TemporaryresponseForm()
return render(request, 'politicalexperimentpollapp/tr.html', {'form': form})
def nr(request, pk):
return render(request, 'politicalexperimentpollapp/nr.html', {'tempresponse': tempresponse})
tr.html template
{% extends 'politicalexperimentpollapp/base.html' %}
{% block extrahead %}
{% load crispy_forms_tags %}
{{ form.media }}
{% endblock extrahead%}
...
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<div><br></div>
<div class="text-center"><button type="submit" class="save btn btn-primary">CONTINUE</button></div>
</form>
..
models.py
class Ethnicity(models.Model):
ethnicity = models.CharField(max_length=200)
def __str__(self):
return '%s' % (self.ethnicity)
...
class Temporaryresponse(models.Model):
birth_year = models.PositiveIntegerField()
voting_registration = models.ForeignKey(Voting_registration, models.SET_NULL, null=True)
party_identification = models.ForeignKey(Party_identification, models.SET_NULL, null=True)
gender = models.ForeignKey(Gender, models.SET_NULL, null=True)
gender_custom = models.CharField(max_length=200, blank=True)
ethnicity = models.ForeignKey(Ethnicity, models.SET_NULL, null=True)
race = models.ManyToManyField(Race)
zip_code = models.IntegerField()
ip = models.CharField(max_length=200, blank=True)
policy_areas_of_importance = models.ManyToManyField(Policy_category, blank=True)
likelihood_of_voting = models.PositiveIntegerField(models.SET_NULL, null=True, blank=True)
Oddly no error shows up in my Chrome console - it's only because I am showing errors on the actual page. I'm not sure if that's normal. Thanks in advance for any help, I'm ripping my hair out at this point.
I discovered that I was using the wrong language for the "race" form field. I had used ModelChoiceField but it should be ModelMultipleChoiceField as follows:
race = forms.ModelMultipleChoiceField(queryset=Race.objects.all(), widget=forms.CheckboxSelectMultiple, label="5. Which of the following best describes your race? Please select all that apply.")
I'm using Django to build a small system to control the lending and borrowing of some stuff our Students Café lend to students.
I'm having trouble identifying an object after a form submit, I want to mark the object as 'unaivalable' (disponible means available, so I want to set it to False) so next time someone comes to ask for THAT object, it will not show up in the 'lending' form.
All I need is a hint on how to achieve it, I've been looking through Django docs, and this site, with no success. Thanks in advance for the tips!
models.py
class Mate(models.Model):
color = models.CharField(max_length=2,
choices=COLOR_CHOICES, default=u'RO')
disponible = models.BooleanField(default=True)
def __unicode__(self):
return self.color
class Prestamo(models.Model):
cliente = models.ForeignKey(Usuario, null=False, blank=False)
mate = models.ForeignKey(Mate, null=False, blank=False)
termo = models.ForeignKey(Termo, null=False, blank=False)
bombilla = models.ForeignKey(Bombilla, null=False, blank=False)
fecha = models.DateTimeField(null=False, blank=False)
devuelto = models.BooleanField(default=False)
fecha_devolucion = models.DateTimeField(null=True, blank=True)
def __unicode__(self):
return str(self.pk)
views.py
#login_required
# Add_prestamo means 'Add lending' this basically deals with prestamo model, but i want to alter 'mate' objects here too.
def add_prestamo(request):
if request.method == 'POST':
form = PrestamoForm(request.POST,
auto_id=False, error_class=DivErrorList)
if form.is_valid():
prestamo = form.save(commit=False)
if request.POST.get('usuarios'):
miuser = request.POST.get('usuarios', '')
else:
miuser = ''
prestamo.cliente = Usuario.objects.get(nombre__exact=miuser)
# I KINDA NEED SOMETHING RIGHT HERE
prestamo.fecha = timezone.now()
prestamo.devuelto = False
prestamo.save()
return HttpResponseRedirect(reverse('list-prestamos'))
else:
form = PrestamoForm()
return TemplateResponse(request,
'gester/add_prestamo.html', {'form': form, })
add_prestamo.html
<form action="" method="post">
{% csrf_token %}
<table>
<tr>
<td>
<div class="ui-widget">
<label for="usuarios">Usuario: </label></td><td>
<input id="usuarios" name="usuarios">
</div>
</td>
</tr>
{{ form.as_table }}
</table>
<input class="btn" type="submit" value="Crear" />
</form>
In the template I show the form with a {{ form.as_table }} it display a select, but many of them (mates) have the same color, so when I get through POST in my view, how do I identify the exact object to alter the 'disponible' field value?
I really don't understand your codes but because you mention disponible, I hope this is what you mean.
prestamo.fecha = timezone.now()
prestamo.devuelto = False
//Because Prestamo model has a foreignkey for Mate model.
//The Mate model contains the disponible field which you want to access
// (to set it to False or unavailable)?
//This is how to access and update it.
prestamo.mate.disponible = False
prestamo.mate.save()
prestamo.save()