I am trying to randomize a query set for a program i'm working on.
This is what's is in my views.py
full_quiz = Quiz.objects.get(name=quiz_name).questions.all()
form = TheForm(full_quiz)
if request.method == "POST":
form = QuestionForm(request.GET, full_quiz)
This is what is in my forms.py
class QuestionForm(forms.Form):
def __init__(self, questions, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
for i in range(len(questions)):
if questions[i].answer.count() < 2:
self.fields["field_name %d" % i] = forms.CharField(label=questions[i], required=False)
From my testing, it appears like the query set is getting randomized with the second form variable. Any fix for this?
Thanks
You can get a random order queryset as described here:
full_quiz = Quiz.objects.get(name=quiz_name).questions.order_by('?')
You have not posted the code of your forms but I expect QuestionForm is a ModelFormSet. You can change the queryset of a ModelFormSet by setting the queryset arg (see docs):
form = QuestionForm(queryset=fullquiz)
Suppose you have a model structure like this
class Quiz(models.Model):
name = models.CharField('Quizname', max_length=200)
questions = models.ManyToManyField('Question')
class Answer(models.Model):
reply = models.CharField('Answer', max_length=100)
class Question(models.Model):
the_question = models.CharField('Question', max_length=100)
answers = models.ManyToManyField('Answer', related_name='answers')
correct_answer = models.ForeignKey('Answer', on_delete=models.CASCADE)
def is_correct(self, given_answer):
return given_answer == self.correct_answer
you could create a form structure with a ModelForm and a ModelFormSet:
class QuestionForm(forms.ModelForm):
myanswers = forms.ModelChoiceField(queryset=Answer.objects.all(), widget=forms.RadioSelect, required=False)
class Meta:
model = Question
fields = ('the_question', 'myanswers')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['myanswers'].queryset = self.instance.answers.all()
QuestionFormSet = modelformset_factory(Question, form=QuestionForm, extra=0)
And use it in a view:
def myview(request, quiz_name):
if request.method == 'POST':
formset = QuestionForm(request.POST)
if form.is_valid():
allanswers = [f['id'].is_correct(f['myanswers']) for f in formset.cleaned_data]
print('Number of correct answers:', sum(allanswers))
fullquiz = Quiz.objects.get(name=quiz_name).questions.order_by('?')
formset = QuestionForm(queryset=fullquiz)
return render(request, 'yourtemplate.html', {'formset': formset })
Related
I am trying to let users create comment from listview on the social app am working on currently but am having a hard time working out the pattern. I keep getting the Error 404 when i try to load the listview. Here is Formlist view which my Post list view inherit from.
class FormListView(FormMixin, ListView):
def get(self, request, *args, **kwargs):
if request.method == 'GET':
post_id = request.GET.get('post_id')
comment = request.GET.get('comment', False)
post_obj = get_object_or_404(Post, pk=post_id)
session_obj = User.objects.get(username=request.user.username)
create_comment = Comment.objects.create(
post=post_obj,
user=session_obj,
comment=comment)
create_comment.save()
# From ProcessFormMixin
form_class = self.get_form_class()
self.form = self.get_form(form_class)
# From BaseListView
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()
if not allow_empty and len(self.object_list) == 0:
raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")
% {'class_name': self.__class__.__name__})
context = self.get_context_data(object_list=self.object_list, form=self.form)
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
if request.method == "POST":
description = request.POST['description']
pic = request.FILES.get('pic', False)
#tag = request.FILES['tag']
user_obj = User.objects.get(username=request.user.username)
post_data = Post(username=user_obj,pic=pic,description=description,)
post_data.save()
messages.success(request, f'Posted Successfully')
return redirect('feed:feed')
return self.get(request, *args, **kwargs)
For one strange thing am able to create New Post from the PostListview but, Comment has been a challenge for me, for the past two weeks now and i have look on here but can't seem to find a solution that fits mine.
class PostListView(FormListView):
model = Post
form_class = NewPostForm
form_class = NewCommentForm
This is my comment model
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
username = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='comments', on_delete=models.CASCADE)
comment = models.CharField(max_length=500)
comment_date = models.DateTimeField(auto_now_add=True)
My Form.py
class NewCommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['comment']
Here is my URL for PostListView.
path('', PostListView.as_view(), name='feed'),
I need to display just the selected value from a forms.ModelChoiceField on a view page. How would I do that?
I've looked at many different forums and couldn't get a clear answer on what I should do in my case. I am new at Python.
form:
class Manufacturer1Form(ReadOnlyFormMixin, ModelForm):
manufacturer = forms.ModelChoiceField(queryset=Vendor.objects.filter(vendor_type='manufacturer').order_by('name'))
class Meta:
model = Manufacturer1Relationship
exclude = ('part',)
model:
class Manufacturer1Relationship(models.Model):
part = models.ForeignKey(Part, on_delete=models.CASCADE)
manufacturer = models.ForeignKey(Vendor, on_delete=models.CASCADE,
limit_choices_to={'vendor_type': 'manufacturer'},)
partNumber = models.CharField(max_length=40, blank=True)
class Meta:
permissions = (
('modify_admin_site', 'Can modify, add, view, or delete manufacturer relationships'),
)
view:
def PartView(request, type_id, id):
partType = Type.objects.get(id=type_id)
instance = get_object_or_404(Part, id=id)
selection = None
if request.method == 'POST':
form = ViewPartForm(type_id, request.POST, request.FILES, instance=instance)
manu1_formset = ManufacturerFormSet(request.POST, instance=instance)
location1_formset = LocationFormSet(request.POST, instance=instance)
if form.is_valid():
selection = form.cleaned_data['active_feed']
part = form.save(commit=False)
part.partType_id = type_id
if manu1_formset.is_valid() and location1_formset.is_valid():
part.save()
manu1_formset.save()
location1_formset.save()
url = reverse('list_parts', args=[partType.pk])
return HttpResponseRedirect(url)
else:
form = ViewPartForm(type_id=type_id, instance=instance)
manu1_formset = ManufacturerFormSet(instance=instance)
location1_formset = LocationFormSet(instance=instance)
return render(request, 'part_view.html', {'view_part_form': form,
'location_formset': location1_formset,
'manu_formset': manu1_formset,
'selection': selection,
'partType': partType,
'part': instance})
class Manufacturer1Form(ReadOnlyFormMixin, ModelForm):
manufacturer = forms.ModelChoiceField(queryset=Vendor.objects.filter(vendor_type='manufacturer').order_by('name'))
class Meta:
model = Manufacturer1Relationship
exclude = ('part',)
def __init__(self, *args, **kwargs):
initial_manufacturer = kwargs.pop("manufacturer",None)
super().__init__(*args, **kwargs)
self.fields["manufacturer"].initial = initial_manufacturer
ManufacturerFormSet(request.POST, instance=instance, manufacturer=specific_manufacturer)
I have trouble getting the current instance's fields on my UpdateView. How do I get the specific instance based on its id?
views.py
class ShowUpdate(UpdateView):
model = Show
fields = ['description', 'season', 'episode']
def post(self, request, **kwargs):
request.POST = request.POST.copy()
request.POST['description'] = "how to get instance description?" # problem here
request.POST['season'] = 2
return super(ShowUpdate, self).post(request, **kwargs)
models.py
class Show(models.Model):
owner = models.ForeignKey(User, null=True, default=True, related_name='o')
title = models.CharField(max_length=100)
description = models.TextField(default='N/A', blank=True, max_length=250)
season = models.IntegerField(default=0)
episode = models.IntegerField(default=0)
def get_absolute_url(self):
return reverse('show:index')
def __str__(self):
return self.title
Look to the UpdateView docs
This View has method get_object(self, queryset=None)
In you case just need to call it in POST method something like this:
class ShowUpdate(UpdateView):
model = Show
fields = ['description', 'season', 'episode']
def post(self, request, **kwargs):
self.object = self.get_object()
request.POST = request.POST.copy()
request.POST['description'] = self.object.description
request.POST['season'] = 2
return super(ShowUpdate, self).post(request, **kwargs)
I am developing a django application which has a form for creating ingredients. The form contains a dropdown for selecting Recipes. When a user creates an ingredient, in the dropdown, I want that only those recipes should appear that are created by the same user.
Here is my code:
#forms.py
class IngredientForm(forms.ModelForm):
primal = forms.BooleanField()
class Meta:
model = Ingredient
fields = ('recipe_id', 'title', 'instructions', 'rules')
#models.py
class Recipe(models.Model):
user = models.ForeignKey('auth.User')
title = models.CharField(max_length=500)
description = models.TextField(max_length=500)
rules = models.TextField(max_length=500,blank=True)
def __str__(self):
return self.title
class Ingredient(models.Model):
user = models.ForeignKey('auth.User')
recipe_id = models.ForeignKey(Recipe, on_delete=models.CASCADE)
title = models.CharField(max_length=500)
instructions = models.CharField(max_length=500)
rules = models.TextField(max_length=500,blank=True)
primal = models.CharField(default='0',max_length=500,blank=True)
def __str__(self):
return self.title
#views.py
def create_ingredient(request):
if request.method == 'POST':
form = IngredientForm(request.POST)
if form.is_valid():
current_user = request.user
data = form.cleaned_data
ingredient_data=Ingredient.objects.create(user=current_user, recipe_id=data['recipe_id'],title=data['title'], primal=data['primal'], instructions=data['instructions'], rules=data['rules'])
ingredient_data.save()
ingredient = Ingredient.objects.get(pk = ingredient_data.pk)
return redirect('ingredient_detail', pk=ingredient.pk)
else:
messages.error(request, "Error")
return render(request, 'create_ingredient.html', {'form': IngredientForm })
The problem is that right now, when the user tries to select a recipe, the recipes created by all users of the site appear in the 'recipe_id' dropdown. He should only be able to see recipes in the dropdown that are created by himself. Any ideas how to do it?
UPDATE FROM ANSWER:
If I use this:
...
if request.method == 'POST':
form = IngredientForm(current_user=request.user, request.POST)
if form.is_valid():
...
it gives me this syntax error: non-keyword arg after keyword arg in this line form = IngredientForm(current_user=request.user, request.POST)
UPDATE#2:
If I use:
...
if request.method == 'POST':
form = IngredientForm( request.POST,current_user=request.user)
if form.is_valid():
...
It gives me error: __init__() got multiple values of argument 'current.user'
If I use:
...
if request.method == 'POST':
form = IngredientForm( request.POST)
if form.is_valid():
...
It gives me error: 'QueryDict' object has no attribute 'id'
UPDATE # 3:
After implementing the latest update from answer. It gives me error name 'current_user' is not defined
in the following piece of code:
def create_ingredient(request):
form = IngredientForm(current_user=request.user)
In the model form you can do this:
class IngredientForm(ModelForm):
primal = forms.BooleanField()
class Meta:
model = Ingredient
fields = ('recipe_id', 'title', 'instructions', 'rules')
def __init__(self, current_user, *args, **kwargs):
super(IngredientForm, self).__init__(*args, **kwargs)
self.fields['recipe_id'].queryset = self.fields['recipe_id'].queryset.filter(user=current_user.id)
then instantiate the form like so
form = IngredientForm(current_user=request.user)
EDIT #1:
Passing in the user to the POST request form:
if request.method == "POST":
form = IngredientForm(request.POST, current_user=request.user)
if form.is_valid():
....
EDIT #2:
Try changing the init decleration to what is below and pop the user from the kwargs:
def __init__(self, *args, **kwargs):
current_user = kwargs.pop('current_user', None)
super(IngredientForm, self).__init__(*args, **kwargs)
if current_user:
self.fields['recipe_id'].queryset = self.fields['recipe_id'].queryset.filter(user=current_user.id)
I think this might solve your problems, leave the rest of the code the same as my answer above (where you create the forms)
I did a lot of search for an issue I am facing, but couldn't find a suitable solution. I am a Django beginner
I am creating a project in which an User will be able to ask a wish, and other users will be assigned that wish, which they can then draw and submit.
I created views for asking and getting a wish, but facing issue while submitting the sketch for the wish. I do not know how to show only those wishes in the add_sketch form for the current user and then update the sketch model with this new sketch.
Right now I am just using a charField for the uploaded sketch. Here is the code
models.py
class Wish(models.Model):
content = models.CharField(max_length=500)
wisher = models.ForeignKey(User)
created_on = models.DateTimeField(auto_now_add=True)
locked = models.BooleanField(default=False)
class Meta():
verbose_name_plural = 'Wishes'
def __unicode__(self):
return self.content
class Sketch(models.Model):
wish = models.ForeignKey(Wish)
sketcher = models.ForeignKey(User)
image_temp = models.CharField(max_length=128)
likes = models.IntegerField(default=0)
assigned_on = models.DateTimeField(auto_now_add=True)
submitted_on = models.DateTimeField(auto_now=True)
class Meta():
verbose_name_plural = 'Sketches'
def __unicode__(self):
return "Sketch for \""+ self.wish.content + "\""
views.py
#login_required
def add_sketch(request):
if request.method == "POST":
sketch_form = SketchForm(request.POST)
if sketch_form.is_valid():
add_sketch = sketch_form.save(commit=False)
add_sketch.save()
return sketchawish(request)
else:
print sketch_form.errors
else:
sketch_form = SketchForm()
return render(request, 'saw/add_sketch.html', {'sketch_form': sketch_form})
And here is the forms.py
class GetWishForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Wish.objects.filter(pk__in = Wish.objects.filter(locked=False)[:3].values_list('pk')), initial=0)
class Meta:
model = Sketch
fields = ('wish',)
class SketchForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Sketch.objects.all(), initial=0)
image_temp = forms.CharField(help_text='Imagine this is an upload button for image, write anything')
class Meta:
model = Sketch
fields = ('wish', 'image_temp')
UPDATE:
I edited the code according to #almalki's suggestion
forms.py
class SketchForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Sketch.objects.all(), initial=0)
image_temp = forms.CharField(help_text='Imagine this is an upload button for image, write anything')
def __init__(self, *args, **kwargs):
super(SketchForm, self).__init__(*args, **kwargs)
self.fields['wish'].queryset = kwargs.pop('wish_qs')
class Meta:
model = Sketch
fields = ('wish', 'image_temp')
views.py
#login_required
def add_sketch(request):
if request.method == "POST":
sketch_form = SketchForm(request.POST)
if sketch_form.is_valid():
add_sketch = sketch_form.save(commit=False)
add_sketch.save()
return sketchawish(request)
else:
print sketch_form.errors
else:
sketch_form = SketchForm(wish_qs=Wish.objects.filter(wisher=request.user))
return render(request, 'saw/add_sketch.html', {'sketch_form': sketch_form})
I still get the error init() got an unexpected keyword argument 'wish_qs'
UPDATE 2:
forms.py remains same as above, here is what I think the views.py should be
#login_required
def add_sketch(request):
if request.method == "POST":
sketch_form = SketchForm(request.POST, wish_qs=Sketch.objects.filter(sketcher=request.user))
if sketch_form.is_valid():
add_sketch = sketch_form.save(commit=False)
add_sketch.save()
return sketchawish(request)
else:
print sketch_form.errors
else:
sketch_form = SketchForm(wish_qs=Sketch.objects.filter(sketcher=request.user))
return render(request, 'saw/add_sketch.html', {'sketch_form': sketch_form})
When I choose a wish, and click submit, the error is: annot assign "": "Sketch.wish" must be a "Wish" instance.
I know this is because the model is expecting a Wish instance, but we are giving a Sketch instance, but I don't know how to achieve what I need. I think some change has to be made in the models.py, connecting Wish and Sketch reversibly.
You need to override the field query set in form initialization:
class SketchForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Sketch.objects.all(), initial=0)
image_temp = forms.CharField(help_text='Imagine this is an upload button for image, write anything')
def __init__(self, *args, **kwargs):
wish_qs = kwargs.pop('wish_qs')
super(SketchForm, self).__init__(*args, **kwargs)
self.fields['wish'].queryset = wish_qs
class Meta:
model = Sketch
fields = ('wish', 'image_temp')
And in your view, you need to pass a queryset filtered based on current logged in user:
sketch_form = SketchForm(request.POST, wish_qs=Wish.objects.filter(wisher=request.user))
and:
sketch_form = SketchForm(wish_qs=Wish.objects.filter(wisher=request.user))