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))
Related
I am making a small project to rate salesmen. I have regions and each region has its salesmen. So, if region "blahblah" is selected, form should show salesmen choices which are related to that region. I have found some answers via stackoverflow, but it still shows all salesmen, regardless of their regions.
My model is this:
class Region(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
def __str__(self):
return self.name
class Salesman(models.Model):
region = models.ForeignKey(Region,
related_name='region',
on_delete=models.CASCADE)
name = models.CharField(max_length=40)
surname = models.CharField(max_length=40)
def __str__(self):
return self.name
class Rating(models.Model):
RATING_CHOICES = [(i, str(i)) for i in range(1,6)]
salesman = models.ForeignKey(Salesman,
related_name='salesman',
on_delete=models.CASCADE)
phone = models.CharField(max_length=15, blank=True)
rating = models.IntegerField(choices=RATING_CHOICES, blank=False)
sent_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.phone
I found modified __init__ method for my forms.py:
class RateAddForm(forms.ModelForm):
class Meta:
model = Rating
def __init__(self, region_id=None, **kwargs):
super(RateAddForm, self).__init__(**kwargs)
if region_id:
self.fields['salesman'].queryset = Salesman.objects.filter(region=region_id)
And also my views.py is this:
def report_add(request, region_id):
if request.method == 'POST':
print(region_id)
form = RateAddForm(request.POST, region_id=region_id)
if form.is_valid():
message = "Thanks!"
form.save()
return HttpResponse(message)
else:
print("Something went wrong!")
form = RateAddForm()
else:
form = RateAddForm(request.POST)
return render(request,
'account/report.html',
{'form': form})
It still shows me all salesmen on my database, even if i choose a region. How to solve this problem that form should show only salesmen of selected region. Thanks in advance!
Try setting the self.base_fields['salesman'].queryset instead of
self.fields['salesman'].queryset (i.e "base_fields" instead of "fields").
(That's what I do when I need to filter in Admin forms)
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 })
I have got the code from https://github.com/adandan01/mybook, the code is working fine, even when I have updated it to Django 2. It's very simple project for adding a person in a form, and his/her relatives in the inline form. Everything works but when I add a relative name and forget to add his relationship, and submitted the form, unfortunately, that record will not pass the validation but will give no error messages as well. Django will ignore the entire record. For example, the record for Hawra in the image, will not be saved and Django will remove it. For this simple App there are only two fields to be filled (name and relationship), but I'm working on app with 8 fields, and it will be difficult to lose the data. is there any way to make django do the validation in the formset/subform as long as any fields have data and will ask the user to fill all required fields?
models.py:
class Profile(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
created_date = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse('profile-update', kwargs={'pk': self.pk})
def __unicode__(self):
return "%s %s" % (self.first_name, self.last_name)
class FamilyMember(models.Model):
profile = models.ForeignKey(Profile, on_delete=models.PROTECT)
name = models.CharField(max_length=100)
relationship = models.CharField(max_length=100)
form.py
class ProfileForm(ModelForm):
class Meta:
model = Profile
exclude = ()
class FamilyMemberForm(ModelForm):
class Meta:
model = FamilyMember
exclude = ()
FamilyMemberFormSet = inlineformset_factory(Profile, FamilyMember,
form=FamilyMemberForm, extra=1)
views.py
class ProfileCreate(CreateView):
model = Profile
fields = ['first_name', 'last_name']
class ProfileFamilyMemberCreate(CreateView):
model = Profile
fields = ['first_name', 'last_name']
success_url = reverse_lazy('profile-list')
def get_context_data(self, **kwargs):
data = super(ProfileFamilyMemberCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['familymembers'] = FamilyMemberFormSet(self.request.POST)
else:
data['familymembers'] = FamilyMemberFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
familymembers = context['familymembers']
with transaction.atomic():
self.object = form.save()
if familymembers.is_valid():
familymembers.instance = self.object
familymembers.save()
return super(ProfileFamilyMemberCreate, self).form_valid(form)
I found the solution here django inline_formset - form.empty_permitted = False doesn't work
I had to add the following code before if (familymembers.is_valid():...) in the create and update class, so, now Django will show the error if I entered data in the Name field only and will tell me the Relationship field is required.
if familymembers.is_valid() == False:
return self.render_to_response(self.get_context_data(form=form,familymembers=familymembers ))
I created a django form (IssueForm) which is meant to be used to register an object which is instance of one of my models (Issue). Following are the model:
model.py
class Issue(models.Model):
TYPE_FIELDS = [
("Math", "Math"),
("Physics", "Physics"),
("Programming", "Programming"),
("Arts", "Arts")
]
issue_text = models.TextField(default="Please insert text")
issue_description = models.TextField(default="Newly created")
issue_deadline = models.DateField()
issue_field = models.CharField(max_length=30, choices=TYPE_FIELDS)
published_by = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
def __str__(self):
return self.issue_description
the form used:
forms.py
class IssueForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
self.user = user
super(IssueForm, self).__init__(*args, **kwargs)
TYPE_FIELDS = [
("Math", "Math"),
("Physics", "Physics"),
("Programming", "Programming"),
("Arts", "Arts")
]
issue_text = forms.CharField(widget=forms.Textarea, required=True)
issue_description = forms.CharField(widget=forms.Textarea, required=True)
issue_deadline = forms.DateField(required=True)
issue_fields = forms.ChoiceField(choices=TYPE_FIELDS, required=True)
class Meta:
model = Issue
fields = [
'issue_text',
'issue_description',
'issue_deadline',
'issue_fields'
]
def save(self, commit=True):
issue = super(IssueForm, self).save(commit=False)
issue.issue_text = self.cleaned_data['issue_text']
issue.issue_description = self.cleaned_data['issue_description']
issue.issue_deadline = self.cleaned_data['issue_deadline']
issue.issue_fields = self.cleaned_data['issue_fields']
if commit:
issue.published_by = self.user
issue.save()
return issue
and the related view:
views.py
def create_issue(request):
if ExtendedUser.objects.filter(user=request.user).exists():
if request.method == 'POST':
form = IssueForm(request.user, request.POST)
if form.is_valid():
form.save()
return redirect("/issues")
else:
form = IssueForm(request.user)
args = {'form': form}
return render(request, "issues/create_issue.html", args)
else:
raise Http404("You are not allowed to perform this action")
The forms works for every field in the model, they are all registered right, except for issue_fields. If i try giving a default value to the field in the model, that is the value that is saved on the database, otherwise I just get an empty field. Also I believe the problem comes from the form used, because if i try to create a new issue from the django admin interface it works just fine.
I feel like it's one of those silly mistakes, but I'm just starting with django and python in general and cannot figure it out on my own.
Thank you for your time!!
The field on your model is called issue_field, but you set issue_fields.
Note that also you are doing far more work here than necessary. Your save method completely duplicates what the superclass does already; you should remove all that code except for the setting of the user value.
enter code hereIf you want to use Choices, you haven't to write one more time list of choices in your forms.py file.
This is an example :
#In your models.py file
LIST_CHOICE = (('A','A'), ('B','B'))
class Test(models.Model) :
foo = models.CharField(choices=LIST_CHOICE, verbose_name="foo")
and
#In your form.py file
TestForm(forms.Modelform) :
class Meta :
model = Test
fields = ['foo']
It's not necessary to overwrite LIST_CHOICE in your form file ;)
So, dont touch to your model.py file, but in your form.py file, just write :
class IssueForm(forms.ModelForm):
issue_text = forms.CharField(widget=forms.Textarea)
issue_description = forms.CharField(widget=forms.Textarea)
def __init__(self, user, *args, **kwargs):
self.user = user
super(IssueForm, self).__init__(*args, **kwargs)
class Meta:
model = Issue
fields = [
'issue_text',
'issue_description',
'issue_deadline',
'issue_fields'
]
Don't forget to remove s in issue_field ;)
I am trying to log the activities during save operation to track all the changes to user model. my approach is as follows.
class User(AbstractUser):
undergrad_college = models.CharField(max_length=20, choices=COLLEGE_CHOICES)
undergrad_degree = models.CharField(max_length=20, choices=COLLEGE_DEGREES)
postgrad_college = models.CharField(max_length=20, choices=COLLEGE_CHOICES)
postgrad_degree = models.CharField(max_length=20, choices=COLLEGE_DEGREES)
currently_working_on = models.TextField()
previous_work_experience = models.TextField()
previous_internship_experience = models.TextField()
def __str__(self):
return self.username
def save(self, *args, **kwargs):
Log(user=User, actions="Updated profile",
extra={"undergrad_college": self.undergrad_college,
"undergrad_degree": self.undergrad_degree,
"postgrad_college": self.postgrad_college,
"postgrad_degree": self.postgrad_degree,
"currently_working_on": self.currently_working_on,
"previous_work_experience": self.previous_work_experience,
"previous_internship_experience": self.previous_internship_experience
})
super(User, self).save(args, **kwargs)
my views are like this for handling the logging.
class ActivityMixin(LoginRequiredMixin):
def get_context_data(self, **kwargs):
context = super(ActivityMixin, self).get_context_data(**kwargs)
context['activities'] = Log.objects.filter(user=self.request.user)
return context
class IndexListView(ActivityMixin, ListView):
template_name = 'pages/home.html'
model = User
I get this error while performing the update action.
Cannot assign "<class 'users.models.User'>": "Log.user" must be a "User" instance.
Update view is as follows
class UserUpdateView(LoginRequiredMixin, UpdateView):
form_class = UserForm
# we already imported User in the view code above, remember?
model = User
# send the user back to their own page after a successful update
def get_success_url(self):
return reverse("users:detail",
kwargs={"username": self.request.user.username})
def get_object(self, **kwargs):
# Only get the User record for the user making the request
return User.objects.get(username=self.request.user.username)
How to assign the User model instance to the Log function. I cant get this working. I am Django newbie.
Looks like pretty straightforward, replace User with self:
Log(user=User, ...
Log(user=self, ...