I have these two models, one Voucher model is a foreign key to the RegistrationForm model. Anytime someone does a search and the item exists in the Voucher model, I want it to be initialized to the Registration form and saved.
Error Message
raise ValueError(
ValueError: Cannot assign "'phr201'": "RegistrationForm.voucher" must be a "Voucher" instance.
Models
class Voucher(models.Model):
name = models.CharField(max_length=120, null=True, blank=True)
class RegistrationForm(models.Model):
voucher = models.OneToOneField(Voucher, on_delete=models.CASCADE)
full_Name = models.CharField(max_length=200,)
Date_of_birth = models.CharField(max_length=100)
View.py
class RegistrationProcessing(generic.CreateView):
form_class = Registerform
template_name = 'RegistrationProcessing.html'
def form_valid(self, form):
form.instance.voucher = self.request.GET.get('q')
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super(RegistrationProcessing, self).get_context_data(**kwargs)
query = self.request.GET.get('q', default='')
print(query.id)
context.update({
'job_listing': Voucher.objects.filter(
Q(name__iexact=query)
)
})
return context
As error says Cannot assign "'phr201'": "RegistrationForm.voucher" must be a "Voucher" instance
You're trying to assign a string to a OneToOne relation you've to pass a instance of Voucher instead of passing string you've to do like this
def form_valid(self, form):
voucher_instance = Voucher.objects.get(name=self.request.GET.get('q'))
form.instance.voucher = voucher_instance
return super().form_valid(form)
here I'm using get so it will raise an exception if given query does not exists you've to handle it in try except block or you can use other way like this
Voucher.objects.filter(name=self.request.GET.get('q')).first()
or use get_object_or_404()
Related
I'm going to do my best not to sound like a real dummy, but no promises. I am a paramedic and I'm trying to make an app to document unit checks electronically.I have a model field that is foreign keyed to a few other models in my project. This field designates the unit the user is staffing for that day. I want the user to choose the unit he/she is staffing that day and have that information auto-fill any forms filled out for that session. I've tried storing the object using sessions and I get this "Object of type 'MedicUnit' is not JSON serializable". I've used the model_to_dict method and tried to pass the string of the unit name through the form_valid method but I get this "Cannot assign "'Medic 2'": "DailyCheck.medic_unit_number" must be a "MedicUnit" instance." I'm relatively new to programming and Django and this seems like a very easy problem to fix, but my google searching skills are not getting me anywhere. Here is my code:
Model.py for the origin of the unit_name model field
class MedicUnit(models.Model):
unit_name = models.CharField(max_length=50, default='')
is_active = models.BooleanField(default=True)
def __str__(self):
return self.unit_name
Model.py for one of the foreign key references to the unit_name
class DailyCheck(models.Model):
daily_user = models.ForeignKey(User, on_delete=models.PROTECT)
record_date = models.DateTimeField(auto_now=True)
medic_unit_number = models.ForeignKey('components.MedicUnit', related_name='medic_unit_number', on_delete=models.PROTECT, default='')
unit_property_number = models.ForeignKey('components.Vehicle', related_name='unit_property_number', on_delete=models.PROTECT, default='')
mileage = models.IntegerField(default=0)
narc_seal_number = models.IntegerField(default=0)
emergency_lights = models.BooleanField()
driving_lights = models.BooleanField()
red_bag = models.BooleanField()
LP_15 = models.BooleanField()
BLS_bag = models.BooleanField()
RTF_bag = models.BooleanField()
suction = models.BooleanField()
oxygen = models.BooleanField()
free_text = models.TextField(default='')
views.py for the directly above model
def check_home_view(request):
if request.method == 'POST':
form = ChooseMedicUnit(request.POST or None)
if form.is_valid():
unit_name = form.cleaned_data.get('medic_unit_number')
request.session['unit_name'] = model_to_dict(unit_name)
print(request.session['unit_name'])
return redirect('daily')
else:
form = ChooseMedicUnit()
return render(request, 'checks/checks_home.html', {'form':form})
class checkAdd(CreateView):
model = DailyCheck
fields = ['unit_property_number', 'mileage', 'narc_seal_number', 'emergency_lights', 'driving_lights', 'red_bag', 'LP_15', 'BLS_bag', 'RTF_bag', 'suction', 'oxygen', 'free_text']
success_url = '/checks'
def form_valid(self, form):
form.instance.daily_user = self.request.user
form.instance.medic_unit_number = self.request.session['unit_name']['unit_name']
return super().form_valid(form)
forms.py
class ChooseMedicUnit(forms.ModelForm):
class Meta:
model = DailyCheck
fields = ['medic_unit_number']
I think you can use MedicUnit.id. This should be sufficient to resolve the issue of initializing the field from the session in other forms:
def check_home_view(request):
if request.method == 'POST':
form = ChooseMedicUnit(request.POST or None)
if form.is_valid():
request.session['unit_name'] = form.cleaned_data.get('medic_unit_number').id # see here
print(request.session['unit_name'])
return redirect('daily')
else:
form = ChooseMedicUnit()
return render(request, 'checks/checks_home.html', {'form':form})
Thank you so much for the answer Andrey. I will try that too. I found that all I had to do was import the MedicUnit model to my view and change my form_valid method to the following:
def form_valid(self, form):
form.instance.daily_user = self.request.user
form.instance.medic_unit_number = MedicUnit.ojbects.get(pk=self.request.session['unit_name']['id'])
return super().form_valid(form)
Apparently sessions cannot store objects since after Django 1.5 I think. Someone may have to fact check me on that. So I referenced an instance of the object with a dictionary value from the model_to_dict data stored in the session with the MedicUnit.object.get call.
If you are having the same problem, you can print the session info to the terminal with a print statement just like in my check_home_view function view. I used that info to see what key was necessary to call primary key number.
I will check Andrey's solution later today and see how well that works. It seems a bit cleaner than my solution.
I know the title says the question has been asked before but the situation is different.
I have something called Agent:
class Agent(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='agents')
...
and a Group:
class Group(models.Model):
agents = models.ManyToManyField('agents.Agent', blank=True, related_name='groups')
now with Django class based views (UpdateView maybe) I want create a view that a user can see only its agents and select only one of them to add it to a specific group.
as far as I get was this
#method_decorator(login_required, name='dispatch')
class GroupAgentRegister(UpdateView):
model = Group
fields = ('agents',)
template_name = 'register.html'
context_object_name = 'group'
def get_form(self, form_class=None):
form = super(GroupAgentRegister, self).get_form(form_class)
form.fields['agents'].queryset = self.request.user.agents.all()
return form
def form_valid(self, form):
if self.object.agents.filter(user=self.request.user):
form.add_error(None, ValidationError(u'Already Registered'))
return super(GroupAgentRegister, self).form_invalid(form)
return super(GroupAgentRegister, self).form_valid(form)
the form rendering is fine except that I'm able to select multiple agents.
but when I select a value and post it it replace the new selected agents with existing ones and it's not appended to the old ones.
I solved it this way. it may help others too.
first I created a form:
class GroupRegistrationForm(forms.ModelForm):
agents = forms.ModelChoiceField(Group.objects.none())
class Meta:
model = Group
fields = ('agents',)
and I changed the register view to this:
#method_decorator(login_required, name='dispatch')
class GroupAgentRegister(UpdateView):
model = Group
form_class = GroupRegistrationForm
fields = ('agents',)
template_name = 'register.html'
context_object_name = 'group'
def get_form(self, form_class=None):
form = super(GroupAgentRegister, self).get_form(form_class)
form.fields['agents'].queryset = self.request.user.agents.all()
return form
def form_valid(self, form):
if self.object.agents.filter(user=self.request.user):
form.add_error(None, ValidationError(u'Already Registered'))
return super(GroupAgentRegister, self).form_invalid(form)
self.object.agents.add(form.cleaned_data['agents'])
self.object.save()
return HttpResponseRedirect(self.get_success_url())
and everything works fine with the most minimal change I had to apply.
In the admin panel, I can add Persons to my CompleteClass model. There is a M2M relationship between CompleteClass and Person. But, my form doesn't work as it should. The pub_date will update, and I can save the head_count, but not the ModelMultipleChoiceField (persons) -- it will not save.
models.py
class Person(models.Model):
name = models.CharField(max_length=255)
persona_description = models.CharField(max_length=255)
def __str__(self):
return self.name
class CompleteClass(models.Model):
persons = models.ManyToManyField(Person)
class_name = models.CharField(max_length=255)
class_head_count = models.IntegerField()
class_pub_date = models.DateField()
def __str__(self):
return '%s %s' % (self.class_name, self.class_head_count)
def save_complete_class(self):
self.class_pub_date = timezone.now()
self.save()
class Meta:
ordering = ('class_pub_date',)
Here is views.py:
def class_new(request):
if request.method == "POST":
form = CompleteClassForm(request.POST)
if form.is_valid():
complete_class = form.save(commit=False)
complete_class.class_pub_date = timezone.now()
complete_class.save()
form.save_m2m()
return redirect('class_detail', pk=complete_class.pk)
else:
form = CompleteClassForm()
return render(request, 'app/class_edit.html', {'form': form})
and forms.py
class CompleteClassForm(forms.ModelForm):
class Meta:
model = CompleteClass
fields = ('class_name', 'class_head_count',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(CompleteClassForm, self).__init__(*args, **kwargs)
self.fields['class_persons']=forms.ModelMultipleChoiceField(queryset=Person.objects.all())
I've read through the documentation and used the save_m2m since i've set commit=false.
The POST data contains person data, but it's not being written to the database. I'm stumped. Please help!
Only fields named in the fields tuple are saved to the instance. You don't have your m2m field listed there.
You also define your modelchoicefield with a different name - class_persons instead of persons. In fact, there is no reason to define that field separately at all - you haven't changed any of the attributes from the defaults.
And once you've removed that definition, there is also no reason to override __init__, seeing as you never pass the user parameter nor do you use it anywhere in the form.
So I'm thinking that this is not the right way to do things, but I am trying to learn django and I am trying some things out. I am trying to set a foreign key for my Formula model, by hardcoding in an instance of maker.
Models:
class Cooker(models.Model):
name = models.CharField(max_length=20, name="name")
background = models.CharField(max_length=500, name="background")
class Formula(models.Model):
food = models.CharField(max_length=200, name="food")
maker = models.ForeignKey(Cooker, related_name="cooker_key")
Views
class CookerCreate(CreateView):
template_name = "cookercreate.html"
model = Cooker
fields = ['name','background']
success_url = reverse_lazy('cooker')
class FormulaCreate(CreateView):
template_name = "formulahome.html"
model = Formula
fields = ['food']
success_url = reverse_lazy('formulahome')
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.maker = Cooker.objects.get(pk=1)
form.save()
return reverse_lazy('formula home')
In the FormulaCreate class where I am setting self.object.maker, I just want to hard code in a Cooker that I already created. Thanks
EDIT: When I try to submit the form in my FormulaCreate(CreateView) I get the error Exception Value: '__proxy__' object has no attribute 'get'
The reason for your error is that form_valid should return a Response object, and you are returning a URL.
Rather than do this manually you should just call the parent method which will redirect to the success_url that you have already defined:
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.maker = Cooker.objects.get(pk=1)
form.save()
return super(FormulaCreate, self).form_valid(form)
If you are using the post method return redirect('formula home') works too.
I have this model:
class Post(models.Model):
thread = models.ForeignKey(Thread)
post_title = models.CharField(max_length=50, blank=True)
# other attributes
And I have a view:
class ThreadView(CreateView):
model = models.Post
template_name = 'forum/thread.html'
fields = ['post_title', 'author', 'post_text']
When I try to send the form I get IntegrityError: NOT NULL constraint failed: forum_post.thread_id.
I think, it's because I foreign key remains empty, but I don't know how to add it automatically.
First, the name of the view you have is not quiet obvious, cause you are trying to create an instance of a Post not of a Thread. Won't it be better to rename it to PostCreateView?
Speaking about the error you get, you are right about foreign key - it is empty. After all, you do not set it anywhere. You should either send it in the form or assign it on validation. The second way is what you are looking for:
class ThreadView(CreateView):
model = models.Post
template_name = 'forum/thread.html'
fields = ['post_title', 'author', 'post_text']
def dispatch(self, *args, **kwargs):
self.thread = get_object_or_404(Thread, pk=kwargs['thread_id'])
return super(ThreadView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
form.instance.thread = self.thread
return super(ThreadView, self).form_valid(form)
I think you must add ForeginKey Feild into Views Feilds
fields = ['thread', 'post_title', 'author', 'post_text']
and be sure there is a data in thread model
Try adding this to your view:
def post(self, *args, **kwargs):
self.t_id = kwargs["t_id"]
return super(ThreadView, self).post(*args, **kwargs)
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.thread = Thread.objects.get(pk=self.t_id)
form.save_m2m()
return super(ModelFormMixin, self).form_valid(form)