So i'm working on an inventory app, a django-app where you can handle inventory in a company. I've been using mostly class-based so far in my views.py, and i can already create and edit all of my models using class-based views.
So when it comes to the generic.DeleteView, i have some problems.
This is my function in views.py:
class DeleteItemView(DeleteView):
model: Item
success_url: reverse_lazy('inventory_app:items')
template_name = 'inventory/detail_pages/item_detail.html'
And this is my URL to the function:
path('items/<int:pk>/delete/', views.DeleteItemView.as_view(), name='delete_item')
When i call this url with a button, this error appears:
DeleteItemView is missing a QuerySet. Define DeleteItemView.model, DeleteItemView.queryset, or override DeleteItemView.get_queryset().
So i heard online that this appears when /<int:pk>/ is missing in the url. But i have it in mine, so whats the problem here?
Thank you already
class DeleteItemView(DeleteView):
model = Item
success_url = reverse_lazy('inventory_app:items')
template_name = 'inventory/detail_pages/item_detail.html'
remove the colon (:) and change to =
Related
I am using the django DeleteView class to delete different entries. The only thing that differs from call to call is the model attribute. It there anyway to have only one call for delete for different models? My suggestion is something along these lines but I don't know how to implement it. Any suggestions?
views.py:
class Delete(DeleteView):
template_name='kammem/delete.html'
success_url=reverse_lazy('forl')
model=super().get_context_data()
def get_context_data(self,**kwargs):
mod=self.kwargs['model']
if mod=='forening':
model=forening
elif mod=='person'
return model
urls.py:
path('delete/<int:pk>/<str:model>',Delete.as_view(),name='delete'),
I want to practice testing on Django, and I have a CreateView I want to test. The view allows me to create a new post and I want to check if it can find posts without a publication date, but first I'm testing posts with published date just to get used to syntax. This is what I have:
import datetime
from django.test import TestCase
from django.utils import timezone
from django.urls import reverse
from .models import Post, Comment
# Create your tests here.
class PostListViewTest(TestCase):
def test_published_post(self):
post = self.client.post('/post/compose/', {'author':"manualvarado22", 'title': "Super Important Test", 'content':"This is really important.", 'published_date':timezone.now()})
response = self.client.get(reverse('blog:post_detail'))
self.assertContains(response, "really important")
But I get this:
django.urls.exceptions.NoReverseMatch: Reverse for 'post_detail' with no
arguments not found. 1 pattern(s) tried: ['post/(?P<pk>\\d+)/$']
How do I get the pk for that newly created post?
Thank you!
You can get it directly from the database.
Note, you shouldn't call two views in your test. Each test should only call the code it is actually testing, so this should be two separate views: one to call the create view and assert that the entry is in the db, and one that creates an entry directly and then calls the detail view to check that it displays. So:
def test_published_post(self):
self.client.post('/post/compose/', {'author':"manualvarado22", 'title': "Super Important Test", 'content':"This is really important.", 'published_date':timezone.now()})
self.assertEqual(Post.objects.last().title, "Super Important Test")
def test_display_post(self):
post = Post.objects.create(...whatever...)
response = self.client.get(reverse('blog:post_detail', pk=post.pk))
self.assertContains(response, "really important")
What you wanna do with testing is using the relyable Django Databse API for recevieng the created data and see if your view represents this data.
As you only create 1 model instance and save it. You may obtain its pk via
model_pk = Post.objects.get(author="manualvarado22").pk
This pk then should be inserted into your url as the Exception states.
But i also recommend abseconded test, where you directly check if the newly created "Post" exists in the DB via django model API.
Edit:
When testing, django or the test Module you are using, creates a clean database only for testing and destroys it after the test-run. So if you want to acces a User while testing you must have created the user in your Test setup or in the Test method itself. Otherwise the Usertable would be empty.
I was finally able to solve the issue thanks to your great answers as well as some extra SO research. This is how the test looks like:
def test_display_no_published_post(self):
test_user = User.objects.create(username="newuser", password="securetestpassword")
post = Post.objects.create(author=test_user, title="Super Important Test", content="This is really important.")
response = self.client.get(reverse('blog:post_detail', kwargs={'pk':post.pk}))
self.assertEqual(response.status_code, 404)
And this are the create and detail views:
class PostDetailView(DetailView):
model = Post
def get_queryset(self):
return Post.objects.filter(published_date__lte=timezone.now())
class PostCreateView(LoginRequiredMixin, CreateView):
login_url = '/login/'
redirect_field_name = 'blog/post_detail.html'
form_class = PostForm
model = Post
I am trying to set up hyperlinking in my Django REST Framework API, and for the life of me I can't find out where my error is.
My model:
class Franchise(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
# Other fields
My serializer
class FranchiseListSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='franchise_details',
lookup_field='id',
lookup_url_kwarg='franchiseid'
)
class Meta:
model = Franchise
fields = ('id', 'name', 'url')
My URLs:
url(r'^db/franchise/$', views.franchise_index, name='db_franchise_index'),
url(r'^db/franchise/(?P<franchiseid>[0-9]+)/$', views.franchise_details, name='db_franchise_details')
Note that this is an included url conf, all my api functionality goes within an /api/ url
My views:
#api_view(['GET'])
def franchise_index(request, format=None):
franchise_list = Franchise.objects.all()
serializer = FranchiseListSerializer(franchise_list, many=True, context={'request': request})
return Response(serializer.data)
#api_view(['GET'])
def franchise_details(request, franchiseid, format=None):
franchise = Franchise.objects.get(id=franchiseid)
serializer = FranshiseDetailSerializer(franchise)
return Response(serializer.data)
Note that FranshiseDetailSerializer seen above works just fine.
Summary:
URL /api/db/franchise/ goes to the view franchise_index, which returns data serialized by FranchiseListSerializer.
URL /api/db/franchise/<franchiseid>/ goes to the view franchise_details, which returns data serialized by FranchiseDetailSerializer (Works fine)
As you can see, I have added a url field to FranchiseListSerializer, which I supposed to link to the corresponding franchise details page. Before I added the url field, the serializer only returned id and name, which was the correct and expected behaviour at the time.
When I go to /api/db/franchise/ now, I get the error:
ImproperlyConfigured at /api/db/franchise/
Could not resolve URL for hyperlinked relationship using view name "franchise_details". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
Following this hint, I set up the arguments in the url field of FranchiseListSerializer, and as far as I can tell, they are correct. I have checked and double checked the DRF documentation, here, here and here, but have found no solution.
Following other similar issues on Stackoverflow, I tried changing view_name='franchise_details' to view_name='api:franchise_details' (the name of the Django app the relevant files are in) and view_name='api:franchise_details-detail', but to no avail.
Any and all help is appreciated, cheers.
Thanks to #AKS's promting, I figured it out. view_name is actually the name of the URL, not the view. From the way I read the documentation (and the fact that it is view_name not url_name), it seemed to say that it was supposed to be the name of the view.
I had actually tried using view_name='db_franchise_details' (my urls name) before, but that did not work. After AKS promted my with that comment, I tried again, and also tried using view_name='api:db_franchise_details', which does work!
So basically what I would like is to have a custom view (print view) for one of my model.
I added a custom button and I changed the get_url() of my model:
def get_urls(self):
urls = super(MyModelAdmin, self).get_urls()
my_urls = patterns('',
url(r'^/print/schedule$',
self.admin_site.admin_view(views.PrintScheduleDetailView.as_view()), name='print_schedule'),
)
return my_urls + urls
When I try to view it:
my_app/my_model/primary_key/print/schedule/
It tells me the object with the pk 1/print/schedule doesn't exist....
What can I do?
Thanks,
Ara
EDIT: Here is my view class:
class PrintScheduleDetailView(generic.DetailView):
model = Tournament
template_name = 'print/schedule.html'
I got the link to kinda work...
localhost/tournament/print/schedule/
works but it tells Generic detail view PrintScheduleDetailView must be called with either an object pk or a slug.... I tried adding a primary key localhost/tournament/print/schedule/pk but didnt work...
Thanks,
Ara
Perhaps the regular expression should be changed to remove the '^' symbol like:
url(r'/print/schedule$'
According to Detailview of class based views:
By default this requires self.queryset and a pk or slug argument
in the URLconf, but subclasses can override this to return any object.
url(r'^/(?P<pk>[\d]+)/print/schedule/$', self.admin_site.admin_view(views.PrintScheduleDetailView.as_view()), name='print_schedule'),)
I believe you need to pass the pk, except if you are fetching it through another way (you haven't pasted your Class View).
I have a model like this:
class EventTypeCategory(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
user = models.ForeignKey(User, verbose_name="User")
Message_slug = models.SlugField(blank=True, verbose_name="Message")
def __unicode__(self):
return self.name
In urls.py:
url(r'^categ/$',
'eventcateg_detail', name='eventcateg_detail'),
In views.py:
def eventcateg_detail(request,event_categ_id=None, event_categ_slug=None):
I want to add/edit/delete(CRUD) above defined value i.e name and Message_slug by template level. I am not getting any hint how to relate url.py with views.py and what should be definition of eventcateg_detail function.How this function will pass values to template (template name will be categ.html)
I am newbie in Django :)
want your help
You need to allow the URL to accept parameters to allow you specify which event category you want to view:
/categ/outdoor-events/
/categ/catered-events/
...
Do do this, you use a named URL pattern in your url scheme:
url(r'^categ/(?P<slug>[-\w]+)/$','eventcateg_detail', name='eventcateg_detail'),
and in your view:
from django.shortcuts import get_object_or_404, render
def eventcateg_detail(request,slug):
return render(request, "categ.html", {
'obj' : get_object_or_404(EventCateg, Message_slug =slug) # You should change Message_slug to just slug
})
and in your template:
<h1>{{ obj.name }}</h1>
So when a user enters a URL like we have outlined above, it gets matched to our URL pattern and the slug part of the url (catered-events) gets passed as a parameter to our view.
It's better that you follow the Django tutorial first, this is all covered in there. See for example part 3 of the tutorial for more information on how to relate urls.py with views.py and part 4 discusses passing variables to the template.
I believe that a view function is only passed an httprequest when it is called by the Django framework, the other two parameters of the function will only be useful if you call the function yourself but will not be useful through the web.
As pointed out in the comments I was mistaken in my belief, extra parameters can be passed as dynamic urls (i.e. urls designated like this url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),. See this link and the answer by #pastylegs
The Django Admin will allow you to edit all model fields if this is what you are after. Instructions on setting it up can be found in the Django documentation.
However I think what you are asking is how to enable CRUD editing through the web to users who are not admin level users. In that case you have many options. One of those options is to use a pre-built framework for Django like piston. Another way would be to use generic views
The other option is to build views yourself enabling operations on your model. In that case all of Django is available to you. You can pass parameters to your custom functions within the httprequest, for example as POST data.