If you have a blog model in Django that saves a slug, how do you create an href link from that slug field?
You should create a view according to Django MVT architecture.
For example you can create a DetailView and associate it with an URL.
# views.py
from django.views.generic.detail import DetailView
from someapp.models import SomeModel
class SomeModelDetailView(DetailView):
model = SomeModel
# urls.py
from django.conf.urls import url
from someapp.views import SomeModelDetailView
urlpatterns = [
url(r'^(?P<slug>[-\w]+)/$', SomeModelDetailView.as_view(), name='somemodel-detail'),
]
And just use the {% url %} template tag to access to this page. For example :
{{ foo.name }}
Where foo is a SomeModel instance.
Related
I've made a class-based view (DetailView) of app user's profile and for some reason anyone who visits the view is automatically considered authenticated even without entering any credentials. This happens without adding any extra logic in neither view nor template, just basic DetailView. The code is below:
views.py
from django.views.generic import DetailView
from django.contrib.auth.models import User
class ProfileDetail(DetailView):
model = User
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
urls.py
from django.urls import path
from .views import ProfileDetail
urlpatterns = [
path('<int:pk>/', ProfileDetail.as_view())
]
template (index.html)
{{ user.is_authenticated }} {# returns True #}
{{ user }} {# returns the user with the corresponding id #}
The question is why does Django do it and is there any way to circumvent it except of using function-based view? I've looked through the docs, but couldn't find an answer.
To implement authentication in Django Class-Based Views, I've used LoginRequiredMixin, as it's explained here:
https://docs.djangoproject.com/es/4.0/topics/auth/default/
Code (from Django site):
from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
login_url = '/login/'
redirect_field_name = 'redirect_to'
Another way is to pass the view that we want to authenticate to the login_required function, in the mapping of urls.py:
from django.contrib.auth.decorators import login_required
path('<int:pk>/', login_required(ProfileDetail.as_view())) #not tested
The simplest way to make any page login_required in class based views is to use method_decoratordjango-doc
In your ProfileDetail you can implement in the following way:
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
method_decorator(login_required(login_url="/any_login_route/"),name='dispatch')
class ProfileDetail(DetailView):
...
...
It will make the page login_required,and set login_url so that it can redirect to login page if user is not authenticated, for more information you can see docs by clicking on above method.
I have a class that passes in a django ListView. From this ListView I can access my DB items. My problem is that accessing the db using the list view will load all the entries. what if I just want one entry, say the 5th entry for example. Maybe listView is the wrong type of view to be using? my code below work and shows my DB entries on-screen as a list.
models.py
from django.db import models
class Datadata(models.Model):
text = models.TextField()
views.py
class HomePageView(ListView):
model = Datadata
template_name = 'hello.html'
templates/hello.html
{% for post in object_list %}
<h1>{{ post.text }}</h1>
{% endfor %}
Then you normally use a DetailView [Django-doc]. You can for example define this as:
from django.views.generic.detail import DetailView
class HomePageView(DetailView):
model = Datadata
template_name = 'hello.html'
You can then render this for example with:
<h1>{{ object.text }}</h1>
What is convenient is that a DetailView, just like all views with a SingleObjectModelMixin [Django-doc] autoamtically filter on the primary key pk or slug field.
So the url pattern should look like:
urlpatterns = [
path('data/<int:pk>/', HomePageView.as_view(), name='data-detail'),
]
If we then access /data/5 for example, it will show the data for the item with as primary key 5.
I have a section of my site where an admin can add a widget. However the delete button to delete any current widgets is not working. I have this code implemented else where on my site and it is working.
I copied the same code from the other section of my site where this is being used. The other section of my site which uses this code is a little different in that a post can only be deleted be the user who created it, and the widgets can be delete by any user with the "access_level" field is equal to "admin". However, I am the only admin so it should still work. The page that the widget stuff is displayed on is only accessible if your "access_level" is equal to admin so I don't need to validate whether or not they have the permission before deleting. Please help.
widget_list.html:
{% extends "base.html" %}
{% block content %}
<div class="container">
<div class="content">
<div class="widgets-list">
{% for widget in widget_list %}
<h3>{{ widget.name }}</h3>
<h3>{{ widget.widget_order }}</h3>
<div>
<p>{{ widget.body }}</p>
</div>
{% if user.is_authenticated %}
<a class="auth-user-options" href="{% url 'adminpanel:delete-widget' pk=widget.pk %}">Delete</a>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
Adminpanel app views.py:
from django.shortcuts import render
from adminpanel.forms import WidgetForm
from adminpanel.models import Widget
from django.utils import timezone
from django.contrib.auth import authenticate,login,logout
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse,reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from braces.views import SelectRelatedMixin
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView)
# Create your views here.
class CreateWidgetView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'index.html'
form_class = WidgetForm
model = Widget
def form_valid(self,form):
self.object = form.save(commit=False)
self.object.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('adminpanel:widgets')
class SettingsListView(ListView):
model = Widget
ordering = ['widget_order']
class DeleteWidget(LoginRequiredMixin,SelectRelatedMixin,DeleteView):
model = Widget
select_related = ('Widget',)
success_url = reverse_lazy('adminpanel:widget')
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
def delete(self,*args,**kwargs):
return super().delete(*args,**kwargs)
Project url spy:
from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
from accounts import views
from colorsets import views
from colors import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.home,name='index'),
url(r'^accounts/',include('accounts.urls',namespace='accounts')),
url(r'^colorsets/',include('colorsets.urls',namespace='colorsets')),
url(r'^adminpanel/',include('adminpanel.urls',namespace='adminpanel')),
]
Adminpanel app urls.py:
from django.conf.urls import url
from adminpanel import views
app_name = 'adminpanel'
urlpatterns = [
url(r'^widgets/',views.SettingsListView.as_view(),name='widgets'),
url(r'^new/$',views.CreateWidgetView.as_view(),name='create-widget'),
url(r'^delete/(?P<pk>\d+)/$',views.DeleteWidget.as_view(),name='delete-widget'),
]
EDIT: Here is the error I'm getting I forgot to add it.
FieldError at /adminpanel/delete/10/
Cannot resolve keyword 'user_id' into field. Choices are: body, id, name, widget_order
and the traceback points to this:
/Users/garrettlove/Desktop/colors/adminpanel/views.py in get_queryset
return queryset.filter(user_id=self.request.user.id) ...
▶ Local vars
Adminpanel app models.py (widget model):
from django.db import models
from adminpanel.choices import *
# Create your models here.
class Widget(models.Model):
name = models.CharField(max_length=50)
widget_order = models.IntegerField(blank=False,unique=True)
display_name = models.IntegerField(choices=WIDGET_NAME_CHOICES,default=1)
body = models.TextField(max_length=500)
def __str__(self):
return self.name
As your error is saying:
Cannot resolve keyword 'user_id' into field.
And it points to this line:
return queryset.filter(user_id=self.request.user.id)
It's that your queryset model does not have a user_id field. In your DeleteWidget view you have specified model = Widget
and as you see in your Widget model, you have the following fields: body, id, name, widget_order. There is no user_id field.
You need to change your filtering logic. If you want to have a related User model, you should use ForeignKey relation and then you can filter by the User's id.
In your models.py:
from django.contrib.auth.models import User
class Widget(models.Model):
# ...
user = models.ForeignKey(User, on_delete=models.CASCADE)
And then in your DeleteWidget's get_queryset, you can do the following:
return queryset.filter(user__id=self.request.user.id)
# __________________________^
# Note that there is a double underscore here!
# This is because Django uses double underscore for accessing related models in queries.
I am trying to use the UpdateView of django but for some reason it does not work.
(URL.py)
from django.conf.urls import url
from . import views
app_name='profiles'
urlpatterns = [
url(r'^$', views.IndexView.as_view(),name='index'),
url(r'^(?P<pk>[0-9]+)$',views.DetailView.as_view(),name='detail'),
url(r'^task/add/$',views.TaskCreate.as_view(),name='task-add'),
url(r'^task/(?P<pk>[0-9]+)$',views.TaskUpdate.as_view(), name='task-update'),
url(r'^task/(?P<pk>[0-9]+)/delete/$',views.TaskDelete.as_view(), name='task-delete'),]
Below is my Html file in which I am trying to add a "Edit" link which will redirect to the UpdateView.
(Details.PY this already has the second url mapped)
{% extends 'profiles/base.html' %}
{% block body %}
<H3>The total efforts are {{datamain.efforts}} {{datamain.status}} hours.</H3>
Edit
{% endblock %}
Below is the Views.py
class IndexView(generic.ListView):
template_name = 'profiles/index.html'
def get_queryset(self):
return Datamain.objects.all()
class DetailView(generic.DetailView):
model = Datamain
template_name = 'profiles/details.html'
class TaskCreate(CreateView):
model=Datamain
fields=['main_task','date_time','efforts','status']
class TaskUpdate(UpdateView):
model=Datamain
fields=['main_task','date_time','efforts','status']
class TaskDelete(DeleteView):
model=Datamain
success_url = reverse_lazy('profiles:index')
fields=['main_task','date_time','efforts','status']
When I run it and go to the page , it shows error "no reverse match"
You forget to pass url argument pk try this:
Edit
This is my first post on Stack Overflow, so I apologize in advance if I am somehow not abiding by the question asking etiquette.
Currently trying to query the database represented by this model,
Models.py
from django.conf import settings
from django.db import models
from django.contrib.auth.models import User
class Things(models.Model):
posted_by = models.ForeignKey(settings.AUTH_USER_MODEL)
thing1 = models.CharField(max_length=30)
thing2 = models.CharField(max_length=30)
thing3 = models.CharField(max_length=30)
by the current user in this view,
Views.py
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.contrib.auth.models import User
from app.models import Things
#login_required(login_url='/login/')
def things(request):
user = request.user
results = Things.objects.filter(posted_by__exact=user)
return render(request, 'my_things.html', {'results' : results})
corresponding to this url,
Urls.py
from django.conf.urls import patterns, include, url
from app import views
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^profile/things/$',views.things),
)
and this template:
my_things.html
{% if results %}
{% for thing in results %}
<h1>{{thing.thing1}} and {{thing.thing2}} and {{thing.thing2}}</h1>
{% endfor %}
{% else %}
<h1>You have no things!</h1>
{% endif %}
The error Django gives me when I try to load the page is an OperationalError saying there is "no such table: app_Things".
After some discussion in the comments, the diagnosis: traditional bugginess with a custom AUTH_USER_MODEL.
Check this: docs especially noting in the first warning the issues you may encounter regarding your database schema. If you're not using a custom user model but are instead just wanting to foreignkey to the built-in User object, you need to from django.contrib.auth.models import User and tie your relations to the User model rather than the thing referenced in settings.
I think you forgot to add your app name in INSTALLED_APPS in settings file and syncdb after that. Also this __exact query is not needed.