I'm trying to pass a molfile as a string to my template that is being generated from a SMILES string so that I can display a chemical structure.
class CompoundView(DetailView):
template_name = 'CompoundDisplay.html'
model = Compound
def get_context_data(self, **kwargs):
context = super(CompoundView, self).get_context_data(**kwargs)
context_object_name = self.get_context_object_name(self.object)
comp_pk = self.kwargs['pk']
if context_object_name:
context[context_object_name] = self.object
comp_id = Compound.objects.get(pk=comp_pk)
cursor = Smile.objects.get(compound_fk=comp_id.compound_ID)
smile = cursor.smiles
m = Chem.MolFromSmiles(smile)
mol = Chem.MolToMolBlock(m)
correct_mol = mol.replace('\n', '\\n')
context['calc_factors'] = cursor
context['mols'] = correct_mol
context.update(kwargs)
return context
Everything is working fine except the mol string, which is getting passed through GET to the page ending up with this in the url, which obviously isn't working. Is there a way in a CBV to load this as POST? Or is there somewhere else I’m going wrong?
[15/Jan/2015 11:20:27] "GET /compounds/compound/298/RDKit%20%20%20%20%20%20%20%20%20%20%2044%2045%20%200%20%200%20%200%20%200%20%200%20%200%20%200%20%200999%20V2000%20%20%20%200.0000%20%20%20%200.0000%20%20%20%200.0000%20O%20%20%200%20%200%20%200%20%200%20%200%20%....2043%20%201%20%200%2043%2044%20%202%20%200%2043%20%202%20%201%20%200%2039%2035%20%201%20%200M%20%20END HTTP/1.1" 404 18005
Related
I have a class that take some info from a form, make some changes to it. And than saves it into database
At the moment all the logic is in the post method. And I want to make the code more structured and I want to put some part of it to a separate method. Is it possible? If so, how can I do it?
here is my code:
class AddSiteView(View):
form_class = AddSiteForm
template_name = 'home.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, { 'form': form })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instanse = form.save()
url = request.POST.get('url', '')
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instanse)
return redirect('checks:robots', pk.id)
return render(request, self.template_name, { 'form': form })
I want to make 2 changes to it:
The 1st thing I want to do is to move this part of code to a separate method
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
And the 2nd thing I want to do is to move this part of code also in a separate method
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instanse)
return redirect('checks:robots', pk.id)
The reason is that I will be adding more functions here. And I don't want to have it all in post method. If it is possible, please, help me. I've already tried several ways of solving this problem, but they didn't work
Thank you
There is nothing special about Django preventing you from using plain python functions. So, if you know how to define methods and functions, you should take the same approach. For example, the first part can be the function
def get_robots_url(url):
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
return url
Then you call the extracted function in the same place
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instance = form.save()
url = request.POST.get('url', '')
url = get_robots_url(url)
....
You can also define a function inside the class - a method, to group the code. For the 2nd part:
class AddSiteView(View):
...
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instanse = form.save()
url = request.POST.get('url', '')
url = get_robots_url(url)
return self.create_robot(site_instanse, url)
return render(request, self.template_name, { 'form': form })
def create_robot(self, site_instance, url):
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instance)
return redirect('checks:robots', pk.id)
I have a Django form that lets users choose a tag from multiple tag options. The problem I am facing is that even when the tag list gets updated, the model form does not get the updated tag list from database. As a result, new tags do not appear in options.
Here is my code in forms.py:
class EnglishTagForm(forms.Form):
tag_choices = [(x.tagName, x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
tag = forms.CharField(widget=forms.Select(choices=tag_choices,
attrs={'class':'form-control'}))
def __init__(self, *args, **kwargs):
super(EnglishTagForm, self).__init__(*args, **kwargs)
self.fields['tag'].choices = [(x.tagName,
x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
This form is being instantiated in view. My question is what changes should I do so that tag_choices gets updated from database on every instantiation.
How the above form is used in views.py:
```
def complaintDetail(request, complaint_id):
complaint = Complaints.objects.filter(pk=complaint_id).first()
context = {}
if request.method == 'POST':
agent = Agent.objects.get(name="English Chowdhury")
if "SubmitTag" in request.POST:
englishForm = EnglishTagForm(request.POST)
if englishForm.is_valid:
// Complaint Delete Logic
return redirect('chatbot:modComplaints')
else:
englishForm = EnglishTagForm()
context['eForm'] = englishForm
elif "SubmitBundle" in request.POST:
newTagForm = NewTagForm(request.POST)
if newTagForm.is_valid():
// Complaint Delete Logic
complaint.delete()
return redirect('chatbot:modComplaints')
else:
newTagForm = NewTagForm()
context['newForm'] = newTagForm
else:
englishForm = EnglishTagForm()
context['eForm'] = englishForm
newTagForm = NewTagForm()
context['newForm'] = newTagForm
context['complaint'] = complaint
return render(request, 'chatbot/complaintDetail.html', context)
```
Edit: (For future reference)
I decided to modify the tag attribute and convert CharField to ModelChoiceField, which seems to fix the issue.
Updated Class:
class EnglishTagForm(forms.Form):
tag = forms.ModelChoiceField(queryset=ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury')),
empty_label=None, widget=forms.Select(
attrs={'class':'form-control'}))
Please remove the list comprehension from Line 2. So that,
tag_choices = [(x.tagName, x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
becomes
tag_choices = []
class Biochemical_analysis_of_blood(CreateView):
model = BiochemicalAnalysisOfBlood
form_class = BiochemicalAnalysisOfBloodForm
template_name = "biochemical_analysis_of_blood.html"
success_url = reverse_lazy("patients")
def get_context_data(self, **kwargs):
context = super(Biochemical_analysis_of_blood, self).get_context_data(**kwargs)
patient = Patient.objects.get(id=1)
context["patient"] = patient
return context
def post(self, request, *args, **kwargs):
analysis = Analyzes()
sid = transaction.savepoint()
analysis.name = request.POST["name"]
analysis.patient_id = Patient.objects.get(id=1)
analysis.who_send = request.POST["who_send"]
analysis.who_is_doctor = request.POST["who_is_doctor"]
analysis.lab_user_id = Doctor.objects.get(id=request.POST["lab_user_id"])
analysis.additional_lab_user = request.POST["lab_user_add"]
analysis.date = '2017-06-18'
analysis.type = 3
analysis.date_analysis = '2017-06-18'
analysis.save()
return super(Biochemical_analysis_of_blood, self).post(request, *args, **kwargs)
I have next algorithm:
Render BiochemicalAnalysisOfBloodForm to the user
When he fills fields and presses button "save" I create a new instance of Analyzes() and fill it programmatically and when in the post method I call super().post() then users data will be written to the model BiochemicalAnalysisOfBlood automatically? But I have next error:
NOT NULL constraint failed:
laboratory_biochemicalanalysisofblood.analysis_id
How can I in hand mode add to the model to the field "analysis" the early created instance of Analyzes()? I don't understand this class to the end where I can find information about all it's opportunities
The main part of your algorithm should reside in your form, because you want to pass the analysis_id to the instance being saved
class BiochemicalAnalysisOfBloodForm(ModelForm):
def save(self, commit=True):
analysis = Analyzes()
sid = transaction.savepoint()
analysis.name = self.data["name"]
analysis.patient_id = Patient.objects.get(id=1)
analysis.who_send = self.data["who_send"]
analysis.who_is_doctor = self.data["who_is_doctor"]
analysis.lab_user_id = Doctor.objects.get(id=self.data["lab_user_id"])
analysis.additional_lab_user = self.data["lab_user_add"]
analysis.date = '2017-06-18'
analysis.type = 3
analysis.date_analysis = '2017-06-18'
analysis.save()
# Your analysis is created, attach it to the form instance object
self.instance.analysis_id = analysis.id
return super().save(commit)
Before doing the super().post you can modify the request.POST data to include your analysis id:
request.POST['analysis_id'] = analysis.id
that might help.
Also note that if the form validation fails in super().post, you will still have created an Analysis object which might not be useful. You could use override the form_invalid method of the CreateView to handle this.
In Django 1.6, I am using a ListView class. This works without paginate_by, but not with. I get object of type 'NoneType' has no len() when I use paginate_by. This is only after the first page, the first page has no issues. I'm not sure why def get_queryset(self) is messing up paginate_by because all it's doing is defining the query_set.
class ViewLog(LoginRequiredMixin, ListView):
template_name = "bot_data/log_view.html"
model = Log
paginate_by = 3
def get_queryset(self):
parameter = self.request.GET.get('search')
user_alpha = self.request.GET.get('user_alpha')
if parameter == "latest":
return Log.most_recent.all()
elif parameter == "oldest":
return Log.least_recent.all()
elif parameter == "ascending":
return Log.user_aplha_ascend.all()
elif parameter == "descending":
return Log.user_aplha_descend.all()
def get_context_data(self, **kwargs):
parameter = self.request.GET.get('search')
context = super(ViewLog, self).get_context_data(**kwargs)
context.update({'current_url': parameter})
return context
EDIT:
I found if I manually append search=ascending as ether /log_view?search=ascending&page=2 or /log_view?page=2&search=ascending in the url window of the browser...both of these combos work. I guess at this point I need to found out how to do the pagination manually and to construct the URL's
I am getting the above error when I have tried to convert my inline_formset to have at least the first row required. (please see here for the StackOverflow question)
My existing code is below:
#views.py
def application(request, job_id):
job = get_object_or_404(Job, pk=job_id)
#return 404 if job isn't yet published
if (job.pub_date>timezone.now() or job.close_date<timezone.now()):
return HttpResponseNotFound('<h1>Job not found</h1>')
#create all the inlineformsets (can_delete) set to false as will always be empty upon population
EducationInlineFormSet = inlineformset_factory(Applicant, Education, extra=1, can_delete=False)
QualificationInlineFormSet = inlineformset_factory(Applicant, Qualification, extra=1, can_delete=False)
EmploymentInlineFormSet = inlineformset_factory(Applicant, Employment, extra=1, can_delete=False)
if request.method == 'POST':
applicant = Applicant(job=job)
form = ApplicantForm(request.POST, instance=applicant)
bottom_form = ApplicantFormBottom(request.POST, instance=applicant)
education_formset = EducationInlineFormSet(request.POST, instance=applicant)
qualification_formset = QualificationInlineFormSet(request.POST, instance=applicant)
employment_formset = EmploymentInlineFormSet(request.POST, instance=applicant)
#check all of the forms and formsets are valid
if form.is_valid() and bottom_form.is_valid() and education_formset.is_valid() and qualification_formset.is_valid() and employment_formset.is_valid():
# save the model to database, directly from the form:
form.save()
bottom_form.save()
education_formset.save()
qualification_formset.save()
employment_formset.save()
return render(request, 'jobs/success.html')
else:
applicant = Applicant(job=job)
form = ApplicantForm(instance=applicant)
bottom_form = ApplicantFormBottom(instance=applicant)
education_formset = EducationInlineFormSet(instance=applicant)
qualification_formset = QualificationInlineFormSet(instance=applicant)
employment_formset = EmploymentInlineFormSet(instance=applicant)
c = {
'job' : job,
'form' : form ,
'bottom_form' : bottom_form,
'education_formset' : education_formset,
'qualification_formset' : qualification_formset,
'employment_formset' : employment_formset,
}
return render(request, 'jobs/application.html', c)
In order to customise the formset I defined the following:
class BaseFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
and pass use it as follows:
EducationInlineFormSet = inlineformset_factory(Applicant, Education, extra=1, can_delete=False, formset=BaseFormSet)
This returns the above error and having read around a lot I'm still none the wiser how I can keep passing an instance to the formset.
Any help would be greatly appreciated.
Regards,
Chris.
I had a similar issue - the problem was the customised formset.
Try subclassing from BaseInlineFormSet (not BaseModelFormSet).
Here is the relevant section of the docs.