I am new to django and I'm making food recipe app. I want the users to be able to add their own recipe.
models.py
from django.db import models
from django.core.urlresolvers import reverse
class Recipe(models.Model):
def __unicode__(self):
return self.recipe_name
recipe_name = models.CharField(max_length=250)
category = models.CharField(max_length=50)
description = models.CharField(max_length=1000)
image = models.CharField(max_length=1000)
prep_time = models.CharField(max_length=250)
difficulty = models.CharField(max_length=50)
instructions_url = models.CharField(max_length=1000)
def get_absolute_url(self):
return reverse('detail', kwargs={'pk': self.pk})
class Ingredients(models.Model):
def __unicode__(self):
return self.ingredients
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredients = models.CharField(max_length=1000)
views.py
class RecipeCreate(CreateView):
model = Recipe
fields = ['recipe_name', 'category', 'image', 'prep_time', 'difficulty', 'instructions_url']
At the moment my form display the fields only from my "class Recipe", but what i want is to have Ingredient field with option to add additional fields. Do you have any suggestions how to do this? Thanks!
It's going to be difficult to do that with the generic CreateView which is meant to create just one instance of a model.
What you want is a view (you could use the generic Django View) with a form (ModelForm) for your Recipe and a formset (see Django formsets) for multiple Ingredients forms. In your View's post method you then validate all the forms and save the data.
In your HTML, you'll need to create additional fields dynamically using javascript and update the number of formsets accordingly (in the formset's management form)
Related
I am querying select related between two models Requirements and Badge Requirement has a related badge indicated by badge_id Models are,
class Badge(models.Model):
level = models.PositiveIntegerField(blank=False, unique=True)
name = models.CharField(max_length=255, blank=False , unique=True)
description = models.TextField(blank=True)
class Meta:
verbose_name = _("Badge")
verbose_name_plural = _("Badges")
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("Badge_detail", kwargs={"pk": self.pk})
""" Requirement Model for requirements """
class Requirement(models.Model):
number = models.PositiveIntegerField(blank=False)
badge = models.ForeignKey(Badge, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
class Meta:
verbose_name = _("Requirement")
verbose_name_plural = _("Requirements")
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("Requirement_detail", kwargs={"pk": self.pk})
In My view I try to join both tables and retrieve. It is,
""" ajax requirements in requirements table """
def get_requirements(request):
requirements = Requirement.objects.all().select_related('badge').values()
print(requirements)
return JsonResponse(list(requirements), safe=False)
The result is,
to the frontend,
to the backend,
Why does it not give me both tables' values?
Best way to achieve that is using Serializers which are the key component to deal with transforming data from models to JSON and the inverse:
To use this approach you can create the following serializers:
yourapp.serializers.py
from rest_framework.serializers import ModelSerializer
from yourapp.models import Requirement, Badge
class BadgeSerializer(ModelSerializer):
class Meta:
model = Badge
fields = '__all__'
class RequirementSerializer(ModelSerializer):
badge = BadgeSerializer()
class Meta:
model = Requirement
fields = '__all__'
After that you should go to your views.py file and do the following changes:
from yourapp.serializers import RequirementSerializer
def get_requirements(request):
reqs = Requirement.objects.select_related('badge')
return JsonResponse(RequirementSerializer(reqs, many=True), safe=False)
In this way you will have a more flexible way to add or remove fields from the serializer, and your application is also going to be more decoupled and easy to maintain.
what I want to achieve is user will submit 3 inputs in the form 1) name 2) dropdown to select technician, 3) multiselect dropdown to select multiple products. Once the user submit the details
it will generate one lead in database with value like name,foreignkey of selected technician and id of selected products in different table. I don't know how to achieve this below I have mentioned my approch to achieve what I want. Please let me know if the models need any changes and how I can write a view for the same.
models.py
class product(models.Model):
name = models.CharField(max_length=20)
class technician(models.Model):
name = models.CharField(max_length=20)
class lead(models.Model):
name = models.CharField(max_length=20)
technician = models.ForeignKey(technician,on_delete=models.SET_NULL,null=True) #only single selection
products = models.ManyToManyField(product) #user can select multiple product in dropdown
form.py
class leadForm(form.ModelForm):
products = forms.MultipleChoiceField(queryset=Product.objects.all())
technician = forms.CharField(max_length=30,choices=[(i.id,i.name) for i in Technician.objects.all().values('id','name')
class Meta:
model = lead
fields = ('name','technician')
You should use a ModelMultipleChoiceField [Django-doc] here. The But in fact you do not need to implement the models yourself. You can simply let the Django logic do the work for you.
In order to give a textual representation at the HTML end, you can override the __str__ functions of the models:
class Product(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Technician(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Lead(models.Model):
name = models.CharField(max_length=20)
technician = models.ForeignKey(Technician, on_delete=models.SET_NULL, null=True)
products = models.ManyToManyField(Product)
Then we can simply define our form with:
class LeadForm(form.ModelForm):
class Meta:
model = Lead
fields = '__all__'
Note: usually classes are written in PamelCase and thus start with an Uppercase.
You can here use a class-based CreateView [Django-doc] for example:
from django.views.generic.edit import CreateView
from app.models import Lead
from app.forms import LeafForm
class LeadCreateView(CreateView):
model = Lead
form_class = LeadForm
template_name = 'create_lead.html'
I want to create a settings page where a user can select multiple values of skills they have. It will have a main category and then subcategories. I need to save those into my database, so I can query them and show their selected skillset again.
I know how to create the MultipleChoiceField but not how to save them to the database. How would I go on about that?
Forms.py
from django import forms
class skills(forms.Form):
jobs = [
('Håndværker', (
('Gulv', 'Gulv'),
('Væg', 'Væg'),
)
),
('Murer', (
('Mur', 'Mur'),
('blabla', 'blabla'),
)
),
]
job = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,
choices=jobs)
Views.py
from .forms import skills
def index(request):
if request.method == 'POST':
form = skills(request.POST)
if form.is_valid():
picked = form.cleaned_data.get('job')
# do something with your results
else:
form = skills
return render(request, 'settings/index.html', {"form":form})
It currently looks like this when the page loads which is good. Next step is just how I would save it to the database, so I can display this again with their previous chosen values.
Since you don't have any models setup yet, you can look into django-multiselectfield, which would store the selected choices "as a CharField of comma-separated values". Then you'd just need to pass those values from your form.
Alternatively you can look into PostgreSQL's Array field.
I would recommend you have a Jobs model and a Skills Model. Then have a skills field on the job model which will be a ManyToManyField to the Skills model. The form for this can then be autogenerated for you by Django as a ModelForm.
# Create your models here.
class Skill(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
def __str__(self):
return self.name
class Job(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
skills = models.ManyToManyField(Skill)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
skills = models.ManyToManyField(Skill)
def __str__(self):
return self.name
You can then add them to the db as
skill1 = Skill.objects.create(name="Skill One")
skill2 = Skill.objects.create(name="Skill Two")
skill3 = Skill.objects.create(name="Skill Three")
skill4 = Skill.objects.create(name="Skill Four")
job1 = Job.objects.create(name="Job One")
job1.skills.add(skill1)
job1.skills.add(skill2)
job2 = Job.objects.create(name="Job Two")
job2.skills.add(skill3)
job2.skills.add(skill4)
Have a form to display
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ["name", "skills"]
You can cutomize the form or the template to your linking
in models.py just create the field with CharField
from django.db import models
class UserProfileInfo(models.Model):
Gender = models.CharField(max_length=10,default='')
in forms.py just create CHOICE like below
class UserProfileInfoForm(forms.ModelForm):
YESNO_CHOICES = (('male', 'male'), ('female', 'female'))
Gender = forms.ChoiceField(choices=YESNO_CHOICES)
class Meta():
model = UserProfileInfo
fields = ('Gender',)
in views.py import this form and display it.
or you can definitely go with
https://pypi.org/project/django-multiselectfield/
I'm on my second Django project. On my first project I used all generic views, with only the most basic forms tied directly to a custom user model using UpdateView.
In this project I'm trying to implement user profile functionality. My custom user model has some extra dummy fields just so I can manipulate the data. This I refer so as the CustomUser model. I also have a UserAddress model containing addresses since a user can have more than one address. I have tried looking for other questions, and I get similar questions, but there is always something missing:
Django class based views - UpdateView with two model forms - one submit
Using Multiple ModelForms with Class-Based Views
Multiple Models in a single django ModelForm?
Django: multiple models in one template using forms
I've spent the last day or two looking for the "Django way" of doing what I want to do and have had no luck. My initial thought was that I could use a single template, fed with two ModelForms wrapped in a single <form> tag. The view would then process each form and update the CustomUser model and create or update the UserAddress models. I have figured out how to mash together the functionality using the base View CBV, but I suspect I'm duplicating a lot of functionality that I could probably find already done in Django. This is my view, where I handle the form instantiating manually, and feed the context.
class UserDetailsView(View):
def get(self, request):
user = request.user
user_basic = CustomUser.objects.get(pk=user.pk)
basic_form = UserBasicForm(instance=user_basic)
user_address = UserAddress.objects.get(user=user.pk)
billing_address_form = UserAddressForm(instance = user_address)
context = {'basic_form':basic_form,'billing_address_form':billing_address_form}
return render(request, 'mainapp/profile.html', context)
My post is the same at this point, as I haven't done the actual validation and saving yet.
class UserBasicForm(forms.ModelForm):
class Meta(forms.ModelForm):
model = CustomUser
fields = (
'username',
'first_name',
'last_name',
)
labels = {
'username':'Username',
'first_name':'First Name',
'last_name':'Last Name',
}
class UserAddressForm(forms.ModelForm):
class Meta(forms.ModelForm):
model = UserAddress
fields = (
'description',
'addressee',
'company',
'address_1',
'address_2',
'city',
'prov_state',
'post_zip',
'country',
)
labels = {
'description':'Address Description',
'addressee':'Addressee',
'company':'Company Name',
'address_1':'Address',
'address_2':'Address 2',
'city':'City',
'prov_state':'Province or State',
'post_zip':'Postal or Zip Code',
'country':'Country',
}
class CustomUser(AbstractUser):
objects = CustomUserManager()
def __str__(self):
return self.email
class UserAddress(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
description = models.CharField(max_length = 256, default='Description')
addressee = models.CharField(max_length = 256,)
company = models.CharField(max_length = 256, default='Self')
address_1 = models.CharField(max_length = 256,)
address_2 = models.CharField(max_length = 256,)
city = models.CharField(max_length = 256,)
prov_state = models.CharField(max_length = 256,)
post_zip = models.CharField(max_length = 256,)
country = models.CharField(max_length = 256,)
def __str__(self):
return self.description
Please go easy on me, I'll take most advice offered.
Edit
After reviewing some other SO questions and Django form examples, it appears that the final answer probably isn't SO material. That said, my observation is that for the Django built-in CBVs, the "best" base view is that which you can minimize or simplify the code you add. Using a TemplateView or FormView for my project in this case just depends on which methods I choose to re-write or override and for that, I'm still open to suggestions.
I'd do something like this (with betterforms):
class UserCreationMultiForm(MultiModelForm):
form_classes = {
'basic': UserBasicForm,
'address': UserAddressForm,
}
class UserDetailsView(View):
template = "mainapp/profile.html"
form_class = UserCreationMultiForm
success_url = reverse_lazy('home')
def form_valid(self, form):
# Save the user first, because the profile needs a user before it
# can be saved.
user = form['basic'].save()
address = form['address'].save(commit=False)
address.user = user
address.save()
return redirect(self.get_success_url())
Then rename your forms in your template to form.basic and form.address
I am trying using django forms and not model forms. While trying to populate data for edit I keep getting keyError (u 'manager'). This does not appear if I remove assignment of a field 'choices'. Choice is a many to many field on my model. to make it less confusing I will paste my model, forms and view.
#model.py
class Choices(models.Model):
choices = models.CharField(max_length=70)
def __unicode__(self):
return self.choices
class UserProfile(models.Model):
user = models.OneToOneField(MyUser)
about_me = models.TextField(max_length=2000, null=True, blank=True)
country = models.CharField(max_length=100,null=True, blank=True)
choices = models.ManyToManyField(Choices, blank=True)
#forms.py
class UserProfileForm(forms.Form):
CHOICES = (
('like to cook', 'like to cook'),
('like only to eat', 'like only to eat')
)
about_me = forms.CharField(widget=forms.Textarea, required=False)
country = forms.CharField(max_length=60,required=False)
choices =forms.MultipleChoiceField(choices=CHOICES,widget=forms.CheckboxSelectMultiple(),required=False)
#views.py
#login_required
def update_profile(request):
userprofile = UserProfile.objects.get(user=request.user)
form = UserProfileForm(initial={'about_me':userprofile.about_me,
'country':userprofile.country,
'choices': userprofile.choices})
return render(request, 'u_profiles/edit_pro.html', {'form':form})
now when I assign the initial value of selected choices I get the keyerror. I would like to know the correct way of doing this.
Thanks.