I'm trying to get all attributes of a single object. I keep getting a "Devices matching query does not exist." I just cannot figure out my issue.
Models.py
`class Devices(models.Model):
category_id = models.ForeignKey(Category, on_delete=models.CASCADE)
device_description = models.CharField(max_length=100)
device_status = models.CharField(max_length=50)
device_date = models.DateTimeField()
device_user = models.CharField(max_length=50)`
Views.py
def view_status(request, pk=None):
device = Devices.objects.get(pk=pk)
return render(request, 'homesite/device_status.html', device)
urls.py
url(r'^viewstatus/$', views.view_status, name='ViewStatus'),
here is the url I use to call http://localhost:8000/homesite/viewstatus/?pk=1
device_satus.html
{% extends "base.html" %}
{% block head %}
<title>Device Status</title>
{% endblock%}
{% block body %}
<h3>Device Status Detail</h3>
{{ devices.device_description }}
{{ devices.device_status }}
{{devices.device_date|date:"Y-m-d H:m:s"}}
{% endblock %}
There are 4 records in my able so I know there is a match for PK=1.
Note, that this is not the usual way to build an URL for accessing a specific object. Below I present first the approach that integrates pk in the URI and second the one passing pk as a parameter.
1. Approach
Here you put the pk in the URI and request something like http://localhost:8000/homesite/viewstatus/1/. If you do so, you need to adapt your urls.py by specifying what part of the URI is the pk you want:
# urls.py
url(r'^viewstatus/(?P<pk>\d+)/$', views.view_status, name='ViewStatus'),
The way you wrote the view is fine:
def view_status(request, pk=None):
if pk is not None:
device = Devices.objects.get(pk=pk)
else:
device = None
return render(request, 'homesite/device_status.html', {'device' : device})
Now, views.view_status will be called with both the request object and the pk as arguments and objects.get will behave as you expected, if the pk you put in the URI exists in you database.
Note that this is the preferred way to get an object.
2. Approach
In this case you pass the pk as a parameter, so call http://localhost:8000/homesite/viewstatus/?pk=1, for example. Now pk is a parameter of a GET request. In this case:
# urls.py
url(r'^viewstatus/$', views.view_status, name='ViewStatus'),
And the view only takes the request object as argument. Within the view you can get the pk as follows:
def view_status(request):
pk = request.GET.get('pk', None)
if pk is not None:
device = Devices.objects.get(pk=int(pk))
else:
device = None
return render(request, 'homesite/device_status.html', {'device' : device})
So in this case your view does not take any arguments other than the request object.
Another issue is in your view function: Django's shortcut render takes a dict object for the optional argument context. Currently you directly pass a Devices object. You need to update your return statement in view_status:
return render(request, 'homesite/device_status.html', {'device' : device})
Hope that helps!
I get an error 'Devices' object is not iterable
urls.py
this is how the url is set up.
url(r'^viewstatus/$', views.view_status, name='ViewStatus'),
but is should be like this
url(r'^viewstatus/(?P<pk>\d+)/$', views.view_status, name='ViewStatus'),
so that I can call like this correct? http://localhost:8000/homesite/viewstatus/1/
views.py
def view_status(request):
pk = request.GET['pk']
device = Devices.objects.get(pk=pk)
return render(request, 'homesite/device_status.html', device
so i need the corresponding views.py code to work with
http://localhost:8000/homesite/viewstatus/1/
I've stared at this for hours so I know I'm missing something simple.
Try changing your view function:
def view_status(request):
pk = request.GET['pk']
device = Devices.objects.get(pk=pk)
return render(request, 'homesite/device_status.html', device)
Let me know if it helps :)
Related
I have 2 Django forms: one, where the user uploads an article, and the second, where the user can edit a list of article words into one of three buckets (change the column value: bucket 1-3).
forms.py
class UploadForm(forms.ModelForm):
class Meta:
model = Upload
fields = ('name','last_name','docfile',)
class Doc_wordsForm(forms.ModelForm):
class Meta:
model= Doc_words
fields= ('id','word','word_type','upload',) #upload is foreign key value
After the user uploads the article, I have a function in views.py that breaks down the uploaded article into a list of words.
I want these words to be looped through and added to a database table(where each row is a word), then have the second form reference these words.
Views.py
# upload_id = (request.GET.get("id"))
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
data = request.FILES['docfile']#.read().decode('UTF-8')
words=get_keywords(data)
results=list(find_skills(words))
for word in results:
form2 = Resume_words(word = word, word_type='exclude', upload = upload_id)
form2.save()
return render(request, 'word_list.html',{
"results":results
})
else:
form = UploadForm()
return render(request, 'upload.html', {
'form':form
})
I having trouble pulling these pieces together and I'm desperate for help of any kind! I having trouble with the following steps:
I don't know how to capture the current users instance when saving to the table. I get an error in the above Views.py code.
I don't know how to have the second form reference the current user from the first form.
Please let me know if I can provide more information or clarity on anything above. Also, feel free to answer one question, or simply point me to where there is an example similar to this, any light shed is greatly appreciated.
There are many ways to get user's info in view. the most basic way (not recommended, AT ALL!) is to pass user's id to every view from every view. for example in login view you pass user's id in context:
return render(request, 'main_page.html',{
"user_id":user.id
})
and make every view get this id whether in url or query parameter.
using url:
urls.py
path('any/pk/', AnyView.as_view(), name='carrot'),
view.py
class AnyView(Views):
def get(request, pk):
user=User.objects.get(pk=pk)
def post(request, pk):
user=User.objects.get(pk=pk)
your_template.html
<!-- post request -->
<form action="{% url 'carrot' user_id %}" method="post">...</form>
<!-- get request -->
<a href={% url 'carrot' user_id %}></a>
using query parameters:
urls.py
path('any/', AnyView.as_view(), name='carrot'),
view.py
class AnyView(Views):
def get(request):
user=request.GET.get('pk', False)
if user:
user=User.objects.get(pk=pk)
def post(request):
user=request.POST.get('pk', False)
if user:
user=User.objects.get(pk=pk)
your_template.html
<!-- post request -->
<form action="{% url 'carrot' %}?pk={{ user_id }}" method="post">...</form>
<!-- get request -->
a much much better way is using django default authentication for log in, log out, permission handling and finally getting user information from request without all this unnecessary code.
view.py
class AnyView(Views):
def get(request):
user=request.user
def post(request):
user=request.user
to implement django authentication check this link:
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Authentication
I'm using Django 2.1.
I'm having a problem with a CreateView because I need to redirect to the update url, but that url contains one argument that is created manually after verifying that the form is valid.
This is the view code:
class ProjectCreateInvestmentCampaignView(LoginRequiredMixin, SuccessMessageMixin, generic.CreateView):
template_name = 'webplatform/project_edit_investment_campaign.html'
model = InvestmentCampaign
form_class = CreateInvestmentCampaignForm
success_message = 'Investment campaign created!'
def get_success_url(self):
return reverse_lazy('project-update-investment-campaign',
args=(self.kwargs['pk'], self.object.campaign.pk, self.object.pk))
def form_valid(self, form):
project = Project.objects.get(pk=self.kwargs['pk'])
form.instance.investment_type = "A"
form.instance.contract_type = "CI"
form.instance.history_change_reason = 'Investment campaign created'
valid = super(ProjectCreateInvestmentCampaignView, self).form_valid(form)
if valid:
campaign = CampaignBase.objects.create(project=project, )
form.instance.campaign = campaign
form.instance.campaign.project = project
form.instance.campaign.creation_date = timezone.now()
form.save()
return valid
As you can see, on the form_valid I validate first the form, and then I create the object campaign and assign all the related data. This is working fine.
The problem came when I changed the get_success_url to fit my use case, that is redirecting to the update view.
I debugged and saw that at the moment I create the variable valid on the form_valid, it checks the success url, and that triggers me the following error:
Exception Type: AttributeError
Exception Value:
'NoneType' object has no attribute 'pk'
Exception Location: /Volumes/Archivos/work/i4b/webplatform/views/investor_campaign_views.py in get_success_url, line 25
I asume that the error is because the campaign is not created yet so it's trying to get the pk from a non existing object.
The thing is that I cannot create the campaign if the form is not validated, but I need the campaign to make the url working (that url is working as it is on the UpdateView that I already have).
It will only invoke get_success_url after form_valid. So it's up to form_valid to create and save the objects needed. If it's valid for them not to be created, you need a different approach. Maybe initialize (say) self.campaign_pk = 0, update it if a campaign can be created with the pk of the campaign object, and let the next view sort out what to do when pk==0. Or,
...
args=(self.kwargs['pk'],
self.object.campaign.pk if self.object.campaign else 0,
self.object.pk))
(I don't fully follow your code so I might be barking up the wrong tree here)
It may be that you don't want CreateView but FormView, which doesn't handle object creation for you, so you may find greater flexibility over how to process a valid form that nevertheless cannot be fully honoured all the time. Or even, just a plain old function-based view, in which you can process two or more forms and be far more able to decide on conditions that constitute non-validity even after all the forms have technically validated.
This is a function-based view structure I have used where I have two forms to process, and a fairly long but boring set of operations to do after BOTH forms validate:
def receive_view( request):
# let's put form instantiation in one place not two, and reverse the usual test. This
# makes for a much nicer layout with actions not sandwiched by "boilerplate"
# note any([ ]) forces invocation of both .is_valid() methods
# so errors in second form get shown even in presence of errors in first
args = [request.POST, ] if request.method == "POST" else []
batchform = CreateUncWaferBatchForm( *args, layout=CreateUncWaferBatchLayout )
po_form = CreateUncWaferPOForm( *args, layout = CreateUncWaferPOLayout, prefix='po')
if request.method != "POST" or any(
[ not batchform.is_valid(), not po_form.is_valid() ]):
return render(request, 'wafers/receive_uncoated.html', # can get this out of the way at the top
{'batchform': batchform,
'po_form': po_form,
})
#it's a POST, everything is valid, do the work
...
return redirect('appname:viewname', ...)
For me, get_success_url was not invoked as the form was not valid (was invalid) and I didn't know. You can override form_invalid(self, form) to control the behavior.
Also, consider this block of code to show any errors in your template
{% if form.errors %}
<div class="alert alert-danger" role="alert">
{% for field, errors in form.errors.items %}
{% for error in errors %}
<b>{{ field }}</b>: {{ error }}
{% endfor %}
{% endfor %}
</div>
{% endif %}
I created a form which will take input and save input values in database(mysql). My forms.py
class postcreation(forms.Form):
post_title = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'name':'post_title'}))
post_name = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'name':'post_name'}))
post_post = forms.CharField(widget=forms.Textarea(attrs={'name':'post_post'}))
My models.py
class postdata(models.Model):
title = models.CharField(max_length=200)
name = models.ForeignKey(userdata, on_delete='CASECADE')
post = models.TextField()
def __str__(self):
return self.title
At first I had not used the 'attr' value. It didn't work. I saw a stackoverflow answer which says that I should. Still no luck.
My views.py
def postinput(request):
if request.method == 'POST':
form = postcreation(request.POST)
if form.is_valid():
inputpost = postdata(title=request.POST['post_title'], name=request.POST['post_name'], post=request.POST['post_post'])
inputpost.save()
return redirect('index')
else:
form = postcreation()
context = { 'form': form }
return render(request, 'firstapp/postinput.html', context)
html template
<form method="POST" action="{% url 'index' %}">
{% csrf_token %}
{{ form }}
<button type="submit">Post</button>
</form>
I was trying to get input through form and save it to database. But I was not being able to do so. I cannot understand why. I was going through some of the tutorials and some stackoverflow questions. It still doesn't work. Thanks for your help.
You can get the values from the validated form instead of the request directly, like this:
# . . .
if form.is_valid()
inputpost = postdata(title=form.cleaned_data.get('title'),
name=form.cleaned_data.get('name'),
post=form.cleaned_data.get('post'))
# . . .
Since postdata.name is a userdata object, you need to point it to one. For example, doing something like this
if form.is_valid()
inputpost = postdata(title=form.cleaned_data.get('title'),
post=form.cleaned_data.get('post'))
name=form.cleaned_data.get('name')
inputpost.name = userdata.objects.get(name=name) # or something similar,
# depending on what exactly
#`userdata` is and how
# to get the relevant instance.
inputpost.save()
I am not sure exactly how to fetch the userdata post, since that depends on the rest of your code, but it's something like that.
It might also be the case that you want to create a new userdata object instead. That would be something like:
# . . .
name=form.cleaned_data.get('name')
ud = userdata(name=name)
ud.save()
inputpost.name = ud,
inputpost.save()
# . . .
Again, depends on what userdata is.
NoReverseMatch at /errorcodes/error_codes/2
Reverse for 'relatedpartsview' with no arguments not found. 1 pattern(s) tried: ['errorcodes\/error_codes\/relatedparts\/(?P[^/]+)$']
Currently I am trying to pass a PK into my link as an argument. However, I keep getting no reverse match. I have added a redirect statement, but that doesn't seem to be resolving the issue.
views.py
class RelatedPartsListView(ListView):
context_object_name = 'related_parts_list'
model = models.ErrorCodes
template_name = 'related_parts_list.html'
def get_context_data(self, **kwargs):
# xxx will be available in the template as the related objects
context = super(ErrorCodeView, self).get_context_data(**kwargs)
context['relatedparts'] = RelatedParts.objects.filter(related_error_code=self.get_object())
return context
return redirect('RelatedPartsListView', pk='pk')
urls.py
urlpatterns = [
path(r'error_codes/',views.ErrorCodeList.as_view(), name='errorcodelist'),
path(r'error_codes/<pk>',views.ErrorCodeView.as_view(), name='errorcodeview'),
path(r'error_codes/relatedparts/<pk>',views.RelatedPartsListView.as_view(), name='relatedpartsview')
]
Link
{% url 'errorcodes:relatedpartsview' %}
Update: I am getting a 'RelatedPartsListView' object has no attribute 'get_object'
class RelatedPartsListView(ListView):
context_object_name = 'related_parts_list'
model = models.ErrorCodes
template_name = 'related_parts_list.html'
def get_context_data(self, **kwargs):
# xxx will be available in the template as the related objects
obj = super(RelatedPartsListView, self).get_context_data(**kwargs)
obj = RelatedParts.objects.filter(related_error_code=self.get_object())
return redirect('related_parts_list', obj.pk)
Your url you are trying to use {% url %} without passing your pk which is wht that url relies on. You can reference the docs here https://docs.djangoproject.com/en/2.0/ref/templates/builtins/
So, you should be passing your object (the one with the pk) to your template through the context. Then you can access that object's pk value. So, you will have something like this.
{% url 'relatedpartsviewurl' obj.pk %}
Edit: Your redirect also does not make any sense and you have two return statements right after each other which makes absolutely no sense.
Edit: Okay, so you need to make your template name in your return redirect the exact same as what is shown in your urls where name= . Next, you need to get rid of your context, rather store your filter as a variable such as obj. Then for your pk in your redirect, just reference that variable like so redirect('template_name', obj.pk)
Edit: CLASS BASED VIEW (idk if works)
Your list view.
class RelatedPartsListView(ListView):
context_object_name = 'related_parts_list'
model = models.ErrorCodes
template_name = 'related_parts_list.html'
def get_context_data(self, **kwargs):
context = super(RelatedPartsListView, self).get_context_data(**kwargs)
context['relatedparts'] = RelatedParts.objects.filter(related_error_code=1)
return context
Replace the relatedparts url with this.
re_path(r'^error_codes/relatedparts/?P<parts_id>[0-9]+',views.RelatedPartsListView.as_view(), name='related_parts_view')
Make your link like this.
{% url 'errorcodes:related_parts_view' 1 %}
Edit: FUNCTION BASED VIEW
views.py
def related_parts_view(request, error_code):
parts = RelatedParts.objects.filter(related_error_code=error_code)
context = {
'relatedparts': parts
}
return render(request, 'path/to/my/template.html', context)
urls.py
re_path(r'^error_codes/relatedparts/?P<error_code>[0-9]+', errorcodes.views.related_parts_view, name='related_parts_view')
other_template.html
Go to Related Parts
template.html
{% for part in relatedparts %}
{{ part.pk }}
{% endfor %}
I have seen similar questions and answers but none that address my problem.
I want my view to perform a User Group check and then pass that via variable to the template. The template will then use that to appear differently to different user groups.
My views.py:
def cans(request):
is_canner = request.user.groups.filter(name='canner') #check if user group = canner
can_list = Can.objects.order_by('name')
context = {'can_list': can_list}
return render(request, 'cans/cans.html', context) #need to return is_canner variable here
And in my template I would use the variable like so:
{% if is_canner %} canner stuff goes here {% endif %}
I'm unsure how to pass this variable, I thought it used context to send it like so:
return render(request, 'cans/cans.html', context({"is_canner": is_canner}))
But this gives me errors - context is not callable.
context is not a function, its an argument to the render function, e.g.
context = {"is_canner": is_canner}
return render(request, 'cans/cans.html', context)
docs: https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render
more background info: Django - what is the difference between render(), render_to_response() and direct_to_template()?