I hope you will give me some advice.
So I can't save Recipe into my database through RecipeCreateForm.
Here is my code:
models.py
class Recipe(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='recipes_created')
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, blank=True)
image = models.ImageField(upload_to='recipes/%Y/%m/%d')
description = models.TextField("Description")
ingredients = models.TextField("Ingredients")
preparation = models.TextField("Preparation")
created = models.DateField(auto_now_add=True, db_index=True)
def __str__(self):
return self.title
forms.py
from django import forms
from .models import Recipe
class RecipeCreateForm(forms.ModelForm):
class Meta:
model = Recipe
fields = ('title', 'image' 'description', 'ingredients', 'preparation')
You are missing an ',' in the forms between 'image' and 'description
This is why the error is 'imagedescription', it is reading both of them as 1 string.
fields = ('title', 'image' 'description', 'ingredients', 'preparation')
with the ',' it will read
fields = ('title', 'image', 'description', 'ingredients', 'preparation')
You need to create a view in views.py file. To create a new object, view will be as shown:
def recipe_create(request):
if request.POST:
form = RecipeCreateForm(request.POST)
new_recipe = form.save() #create a new instance in model form
else:
form = RecipeCreateForm()
context = {'form':form}
template = 'xyz.html'
return render(request, template, context)
If request is post i.e you are saving data from the form to database. And if request is get you are rendering an empty form.
Related
I have a question here
I have two models
Tag Model
class Tag(models.Model):
creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='author')
name = models.CharField(max_length=100)
def __str__(self):
return self.name
Profile Model
class Profile(models.Model):
profiler = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='contour')
bio = models.TextField(blank=True, null=True)
tags = models.ManyToManyField(Tag, blank=True, related_name='keywords')
image = models.ImageField(default='avatar.jpg', upload_to='images', blank=True, null=True)
def __str__(self):
return f'{self.profiler}'
Tag Serializer
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = '__all__'
Profile Serializer
class ProfileSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = Profile
fields = ['id', # List All fields Exclude profiler => OneToOne field name
'bio', 'description',
'tags',
'image',
'birthDate', 'created', 'updated',
]
depth = 1
Profile Viewset
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
permission_classes = [IsAuthenticated]
def partial_update(self, request, *args, **kwargs):
data = request.data
profile_obj = Profile.objects.update(
profiler=self.request.user,
bio=data['bio'],
image=data['image'],
)
profile_obj.save()
for tag in data['tags']:
tag_obj = Tag.objects.update_or_create(
creator=self.request.user,
name=tag['name'], # name => Field Name in Tag Model
)
print(tag_obj)
profile_obj.tags.add(tag_obj) # tags => ManyToMany Field Name in Profile Model
serializer = ProfileSerializer(profile_obj)
return Response(serializer.data)
my aim is to create a new tag if this name is not exist, and also update profile tags
but my code is not working, and I don't know why
Can Any body help please ?
Finally I found the solution, But it still missing some steps
Profile Serializer
class ProfileSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True) # tags = ManyToMany Field Name
class Meta:
model = Profile
fields = ['id', # List All fields Exclude profiler => OneToOne field name
'bio', 'description',
'tags',
'image', 'get_image',
'birthDate', 'created', 'updated',
]
def update(self, instance, validated_data):
# Clear Existing Tags List Before Creating a New One By user
instance.tags.clear()
tags_data = validated_data.pop('tags')
instance = super(ProfileSerializer, self).update(instance, validated_data)
for tag_data in tags_data:
tag_qs = Tag.objects.filter(name__iexact=tag_data['name'])
if tag_qs.exists():
tag = tag_qs.first()
else:
tag = Tag.objects.create(**tag_data, creator=self.instance.profiler)
instance.tags.add(tag)
return instance
It Worked Like a charm but the problem is:
when I want to partial update of fields and i did't submit tags field,
It raises error
{
"tags": [
"This field is required."
]
}
Can some one help to keep my tags list as it is when the updated data missing tags field
Thanks in-advance
I have a simple Django 3.1.0 app I need to create in order to assign Tasks with Tags (or assign tags into tasks).
My Model
class Task(models.Model):
user = models.CharField(max_length=33)
time = models.DateTimeField(auto_now_add=True)
task = models.CharField(max_length=500)
tags = models.ForeignKey('Tag', on_delete=models.SET_NULL, null=True)
class Tag(models.Model):
tag = models.CharField(max_length=30, default="No Tag")
members = models.ManyToManyField('Task')
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
My Form
class TaskForm(ModelForm):
class Meta:
model = Task
fields = ['user', 'task', 'tags']
template_name = 'tasks.html'
tags = ModelMultipleChoiceField(
queryset=Tag.objects.values().all(), widget=CheckboxSelectMultiple()
)
My View
def main(request):
model = Task.objects.values().all()
form = TaskForm()
con = {'context': list(model), 'form': form}
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
form.save_m2m()
return redirect('/')
else:
form = TaskForm()
return render(request, "tasks.html", con)
The migrations are successfull, and with the above code, the view shows a checkbox list with the fetched tags, but the problem is that when I hit Submit on the form, the values are not saved/written on the database but the page reloads successfully.
However, if I turn the following:
obj = form.save(commit=False)
form.save_m2m()
into
form.save(commit=True)
#form.save_m2m()
the values are written only from the fields 'user', 'task' - without the 'tags'
It's also funny that what fetches back on the webpage as values of the tags is in the shape of:
[checkbox] {'id': 1, 'tag': 'aks'}
What am I doing wrong? Thanks.
UPDATE after a comment below:
As Abdul Aziz suggested, I had to remove the values() from the queryset. But after that , to make it work, I had to add also:
In the model:
tag = models.CharField(max_length=100, default="No Tags")
and then refer to that one in the form and Vue template.
You have a ForeignKey set to the Tag model on your Task model, when you actually want a ManyToMany relationship between them. Remove the foreign key and set a related_name to the ManyToManyField in the Tag model like so:
class Task(models.Model):
user = models.CharField(max_length=33)
time = models.DateTimeField(auto_now_add=True)
task = models.CharField(max_length=500)
class Tag(models.Model):
tag = models.CharField(max_length=30, default="No Tag")
members = models.ManyToManyField('Task', related_name="tags")
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
Also in your form you have:
tags = ModelMultipleChoiceField(
queryset=Tag.objects.values().all(), widget=CheckboxSelectMultiple()
)
Why are you using values here? Remove it:
tags = ModelMultipleChoiceField(
queryset=Tag.objects.all(), widget=CheckboxSelectMultiple()
)
I have a model :
from django.db import models
from tinymce.models import HTMLField
class Team(models.Model):
name = models.CharField(max_length=100, verbose_name='Team name')
city = models.CharField(max_length=100, verbose_name='Team city')
biography = HTMLField(verbose_name='Team biography')
country = models.ForeignKey('Country')
slug = models.SlugField(max_length=100)
def __str__(self):
return self.name
class Country(models.Model):
name = models.CharField(max_length=100, verbose_name='Country name')
code = models.CharField(max_length=5, verbose_name='Country code')
def __str__(self):
return self.code
And a form for this model:
from django import forms
from teams.models import Team
class TeamForm(forms.ModelForm):
class Meta:
model = Team
fields = (
'biography',
'city',
'country'
)
And this is my view:
def add(request):
if request.method == 'POST':
form = TeamForm(request.POST)
if form.is_valid():
send = True
form.save()
else:
form = TeamForm()
return render(request, 'teams/add.html', locals())
As you can see, all my model fields are required because I don't add argument 'null' to True in my model attributes.
In my ModelForm, for testing, I just specify fields biography, city and country.
But when I fill the form and send-it, data are saved in database, however is missing name and slug....
Why dont i have a django exception ?
Thanks for youre help
Neither of those fields are saved as Null, though. They are both character fields (SlugField is a subclass of CharField), and an empty charfield is saved as an empty string - which is perfectly valid from the database point of view.
I'm trying to create a form where the user can select multiple technician. When I add the line technician = forms.SelectMultiple(label='Technicians Involved') to my forms.py I get a big blank box with no data. How can I populate that box with the technicians from the User model?
models.py
class Incident(models.Model):
user_id = models.ForeignKey(User, related_name='user')
technician = models.ForeignKey(User, related_name='technician')
capa = models.CharField('capa number', max_length=9)
forms.py
class IncidentForm(forms.ModelForm):
###################### TRYING! ################################
technician = forms.SelectMultiple(label='Technicians Involved')
###############################################################
class Meta:
model = Incident
fields = [ 'user_id',
'technician',
'capa',
]
views.py
def report_incident(request):
template = "report.html"
if request.method == 'POST':
form = IncidentForm(request.POST)
if form.is_valid():
# Auto capturing logged in user
incident = form.save(False)
incident.user_id = request.user
incident.save()
return HttpResponseRedirect('/incidents/')
else:
form = IncidentForm() #an unbound form
return render(request, template, {'form': form})
************** UPDATE WITH CORRECTIONS I MADE BELOW *********************
models.py
class Incident(models.Model):
user_id = models.ForeignKey(User, related_name='user')
technician = models.ManyToManyField(User, related_name='technician')
capa = models.CharField('capa number', max_length=9)
forms.py
class IncidentForm(forms.ModelForm):
technician = forms.SelectMultiple()
class Meta:
model = Incident
fields = [ 'user_id',
'technician',
'capa',
]
views.py
No changes
admin.py
Changes made to view multiple technicians per incident in the admin interface.
class IncidentAdmin(admin.ModelAdmin):
list_display = ('id',
'user_id',
'capa',
'get_technicians'
)
def get_technicians(self):
return "\n".join([t.technicians for t in obj.technician.all()])
Try this out
class IncidentForm(forms.ModelForm):
technician = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=User.objects.all())
class Meta:
model = Incident
fields = [
'technician',
'capa',
]
I am working on a cookbook website using django and have run into a problem with a foreign key field in my form
the problem is that when i create my recipe i need to have a foreign key pointing to the cookbook that created this recipe but I don't want the user creating the recipe to see the original_cookbook field (they shouldn't have to)
I believe I need to use a widget (HiddenInput) but am I getting confused with the examples given on other sites. Also my friend mentioned something about setting an initial value in the original_cookbook view
tl;dr: I want to point the fk to the users cookbook while keeping the original_cookbook field hidden.
relevant code:
form:
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
model:
class Recipe(models.Model):
def __unicode__(self):
return self.name
original_cookbook = models.ForeignKey(Cookbook)
#cookbooks = models.ManyToManyField('Cookbook', related_name = 'recipes')
name = models.CharField(max_length=200)
author = models.CharField(max_length= 100)
picture = models.ImageField(upload_to = 'Downloads', blank=True)
pub_date = models.DateTimeField('date published', auto_now_add=True, blank=True)
ingredients = models.TextField()
steps = models.TextField()
prep_time = models.IntegerField()
TYPE_CHOICES= (
('SW', 'Sandwich'),
('AP', 'Appetizers'),
('SD', 'Sauces and Dressings'),
('SS', 'Soups and Salads'),
('VG', 'Vegetables'),
('RG', 'Rice, Grains and Beans'),
('PA', 'Pasta'),
('BR', 'Breakfast'),
('MT', 'Meat'),
('SF', 'Seafood'),
('BP', 'Bread and Pizza'),
('DT', 'Desserts'),
)
type = models.CharField(max_length = 2, choices=TYPE_CHOICES)
def index_queryset(self):
return self.objects.all()
view:
def createrecipe(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/index/')
else:
if request.method == 'POST':
form = RecipeForm(request.POST)
if form.is_valid():
recipe = form.save()
user = request.user
cookbooks = user.cookbooks
cookbook = cookbooks.all()[0]
cookbook.recipes.add(recipe)
return HttpResponseRedirect('/account')
else:
form = RecipeForm()
return render_to_response('cookbook/createrecipe.html',
{'form':form},
context_instance=RequestContext(request))
Add exclude = ('original_cookbook',) to your form's Meta class.
Then, in your if form.is_valid() code, do something like:
....
recipe = form.save(commit=False)
recipe.original_cookbook = whatever_that_is
recipe.save()
...
This is answered in the documentation.
from django import forms
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
widgets = {'cookbook': forms.HiddenInput