Django set slug in view - django

can anyone tell me how to set a slug in a view?
I pretend to use name as slug,
def editar_cliente(request, pk):
detail = database.objects.get(pk=pk)
name = detail.name
company = detail.company
pk = detalle.pk
return render(request, 'edit_client.html'company': company, 'pk':pk})

I would create slug in the model's save method:
from django.utils.text import slugify
class Client(models.Model):
name = models.CharField(max_length=30)
slug = models.SlugField(editable=False) # hide from admin
def save(self):
if not self.pk:
self.s = slugify(self.name)
super(Client, self).save()
But you could use the same approach to set it in view as well:
from django.utils.text import slugify
def editar_cliente(request, pk):
detail = database.objects.get(pk=pk)
name = detail.name
company = detail.company
pk = detalle.pk
slug = slugify(name)
return render(request, 'edit_client.html'company': company, 'pk':pk})
Hope it helps.

Related

Django - Class Based View trouble How Combine DetailView with ListView in same template

can anyone tell me how combine detailview with list view and show info in the same template, i'll explain you, i'm learning Django and i am trying to create a Questions and Answer web app, and i need to show the question with all its awnsers, i need in my detailview for a specific question show below all it awsers, something like stackoverflow does
#models.py
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
# Create your models here.
class Question(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="question", null=True)
name = models.CharField(max_length=100)
description = models.TextField(max_length=100)
date = models.DateTimeField(auto_now_add=True)
cant_resp = models.IntegerField(default=0)
question_type = models.CharField(max_length=50, choices=QUESTION_TYPES_CHOICES)
def __str__(self):
return self.description
class Anwser(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="anwser", null=True)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.TextField(max_length=400)
date= models.DateTimeField(auto_now_add=True)
#and this are my views.py
from django.shortcuts import render, redirect
from django.urls import reverse, reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from .forms import QuestionForm, AnwserForm
from .models import Question
# Create your views here.
class QuestionListView(LoginRequiredMixin, generic.ListView):
template_name = 'anwserquestions/question_list.html'
context_object_name = 'questions'
def get_queryset(self):
return Question.objects.all()
def createquestion(response):
if response.method == "POST":
print("Its POST method")
form = QuestionForm(response.POST)
# user =response.user
if form.is_valid():
name = form.cleaned_data["name"]
description=form.cleaned_data['description'],
question_type=form.cleaned_data['question_type'],
# date=form.cleaned_data['date'],
t = Question(name=name, description=description, question_type=question_type, cant_resp=0)
t.save()
response.user.question.add(t) # adds the to do list to the current logged in user
# return HttpResponseRedirect("/%i" %t.id)
return redirect('anwserquestions:question-list')
else:
form = QuestionForm()
return render(response, "anwserquestions/question_create.html", {"form":form})
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_queryset(self):
return Question.objects.all()
class QuestionDeleteView(LoginRequiredMixin, generic.DeleteView):
template_name = 'anwserquestions/question_delete.html'
context_object_name = 'question'
success_url = reverse_lazy('anwserquestions:question-delete')
# def get_queryset(self):
# return Question.objects.all()
You can get the related answers by including it in the views context, so you QuestionDetailView becomes
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_context_data(self, **kwargs):
context = super(QuestionDetailView, self).get_context_data(**kwargs)
context['answers'] = Answer.objects.filter(post=self.get_object())
return context

One view for two models with redirect

I have Django app with the following model:
class Author(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
This is now using simple generic view:
class AuthorDetail(DetailView):
model = Author
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# some additional context thingies
return context
and with the following URL configuration:
path('author/<slug:slug>/', AuthorDetail.as_view(), name='author-detail'),
Now I want to introduce simple aliases for authors, so for example instead of /author/william-shakespeare I can reach the page also as /author/ws or /author/my-favourite-author.
I came up with this idea (I know that destination could be key to Author, but that (I think) would not change much in the case):
class AuthorAlias(models.Model):
slug = models.SlugField(max_length=200, unique=True)
destination = models.CharField(max_length=200)
So to achieve the redirect I came up with the following in the view:
def get(self, request, **kwargs):
slug = kwargs['slug']
try:
self.object = self.get_object()
except Http404:
self.object = get_object_or_404(AuthorAlias, slug=slug)
return redirect(reverse('author-detail', args=[self.object.destination]))
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
Everything seems to be working fine, but I was wondering it there is a better approach and if this approach can cause any issues I'm not seeing?
The problem here is that destination does not per se refer to a real author. You can alter this by using a ForeignKey instead:
class AuthorAlias(models.Model):
destination = models.ForeignKey('Author', on_delete=models.CASCADE)>
slug = models.SlugField(max_length=200, unique=True)
In the Author class it might be better to implement the get_absolute_url(…) method [Django-doc] to define a canonical url:
from django.urls import reverse
class Author(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
def get_absolute_url(self):
return reverse('author-detail', kwargs={'slug': self.slug})
Now we can implement the DetailView with:
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect
class AuthorDetail(DetailView):
model = Author
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# some additional context thingies
return context
def get(self, request, *args, **kwargs):
try:
self.object = self.get_object()
except Http404:
return redirect(get_object_or_404(
Author,
authoralias__slug=self.kwargs['slug']
))
context = self.get_context_data(object=self.object)
return self.render_to_response(context)

Redirection issue using PK

I Have a very strange phenomenon
In my app the user Create a project and is redirected to that project detail using its pk. On that project detail page he is asked to create a team and when the team is created he is redirected again to the project detail page but to the wrong pk
for example: I just created a project and I got redirected to .../project/24. I was asked to create a team, I created it but got redirected to ../project/17 any idea why and how to redirect my page to the right URL ?
model.py:
class Team(models.Model):
team_name = models.CharField(max_length=100, default = '')
team_hr_admin = models.ForeignKey(MyUser, blank=True, null=True)
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs = {'pk' : self.pk})
def __str__(self):
return self.team_name
class TeamMember(models.Model):
user = models.ForeignKey(MyUser)
team = models.ForeignKey(Team)
def __str__(self):
return self.user.first_name
class Project(models.Model):
name = models.CharField(max_length=250)
team_id = models.ForeignKey(Team, blank=True, null=True)
project_hr_admin = models.ForeignKey(MyUser, blank=True, null=True)
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs = {'pk' : self.pk})
def __str__(self):
return self.name
views.py
class TeamCreate(CreateView):
model = Team
fields = ['team_name']
template_name = 'team_form.html'
def form_valid(self, form):
valid = super(TeamCreate, self).form_valid(form)
form.instance.team_hr_admin = self.request.user
obj = form.save()
#SELECT * FROM project WHERE user = 'current_user' AND team_id = NULL
obj2 = Project.objects.get(project_hr_admin=self.request.user, team_id=None)
obj2.team_id = obj
obj2.save()
return valid
return super(TeamCreate, self).form_valid(form)
def get_success_url(self):
project = Project.objects.get(team_id=self.obj, project_hr_admin=self.request.user)
return project.get_absolute_url()
The problem here is your CreateView is refering to a TeamObject and not project.
You should override the get_success_url method:
def get_success_url(self):
project = Porject.objects.get(team_id=self.object, project_hr_admin=self.request.user)
return project.get_absolute_url()
The function called was the get_absolute_url of your Team model. So you're calling the project detail view but with the team pk => you get a random project assuming there's a project with a pk which has the same value as your project or, the pk you're sending doesn't exist and you'll have a 404 error (pk doesn't exist).
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs = {'pk' : self.pk})
That's the one in your Team model, but you call ProjectDetails. So here, self.pk is Teaminstance.pk.
What I do in the code i gave you is to call the get_absolute_url of the project instance.
But as told in the other answer, you should remove or change your get_absolute_url of your team model.
class Team(models.Model):
# ...
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs = {'pk' : self.pk})
^^^^^^^
Here, the wrong pk will be delived. Thx to #Bestasttung for clarification

Auto Generated Slugs in Django Admin

I have an app that will one day allow front-end crud, which will create the slug with slugify. Right now though, all the object creation is being done in the admin area and I was wondering if there is a way to auto generate slugs while creating and saving an object from within admin?
Here is the method for slugify for the front-end; not sure if its even relevant. Thank you.
def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = Veteran.objects.filter(slug=slug).order_by('-id')
exists = qs.exists()
if exists:
new_slug = '%s-%s' % (slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug
Having just used this on another answer, I have exactly the right code in my clipboard. I do exactly this for one of my models:
from django.utils.text import slugify
class Event(models.Model):
date = models.DateField()
location_title = models.TextField()
location_code = models.TextField(blank=True, null=True)
picture_url = models.URLField(blank=True, null=True, max_length=250)
event_url = models.SlugField(unique=True, max_length=250)
def __str__(self):
return self.event_url + " " + str(self.date)
def save(self, *args, **kwargs):
self.event_url = slugify(self.location_title+str(self.date))
super(Event, self).save(*args, **kwargs)
Above solutions break validation in the Django Admin interface. I suggest:
from django import forms
from django.http.request import QueryDict
from django.utils.text import slugify
from .models import Article
class ArticleForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs)
# Ensure that data is a regular Python dictionary so we can
# modify it later.
if isinstance(self.data, QueryDict):
self.data = self.data.copy()
# We assume here that the slug is only generated once, when
# saving the object. Since they are used in URLs they should
# not change when valid.
if not self.instance.pk and self.data.get('title'):
self.data['slug'] = slugify(self.data['title'])
class Meta:
model = Article
exclude = []

Would using a foreign key help me in this example?

I'm confused about how to pull in related information from two different tables.
If I go to localhost:8000/user/username, it should display the users profile and user reviews below. because the username is being passed through the URL into the views function. Is that correct?
Also, is it required that I use foreign key to accomplish this? I've read the docs and I'm still not completely sure how a foreign key would help me accomplish my goal here.
Models
from django.db import models
class User(models.Model):
name = models.CharField(max_length=20)
reviewer = models.CharField(max_length=20)
password = models.TextField()
zipcode = models.Charfield(max_length=100)
email = models.EmailField()
def __str__(self): # __unicode__ on Python 2
return self.name
class UserReview(models.Model):
name = models.ForeignKey(User)
author = models.CharField(max_length=50)
pub_date = models.DateField()
stars = models.IntegerField(max_length=5)
comment = models.CharField(max_length=100)
def __str__(self): # __unicode__ on Python 2
return self.name
Views
from django.shortcuts import render
def index(request):
profile_info = User.objects.filter(name=username)
context = {‘profile_info’: profile_info}
latest_reviews = UserReview.objects.filter(name=username).order_by('-pub_date')[:5]
context = {‘profile_info’: profile_info, 'latest_reviews': latest_reviews}
return render(request, 'randomtemplate.html', context)
URLS
urlpatterns = patterns('',
url(r'^user/(?P<username>\w+)/', 'index'),
)
There's a couple things you need to do. The first is that you need to pass the parameter into the view function, and then you'll need to display the ratings in the template.
#view
def index(request, username):
profile_info = User.objects.filter(name=username)
latest_reviews = UserReview.objects.filter(name=username).order_by('-pub_date')[:5]
context = {‘profile_info’: profile_info, 'latest_reviews': latest_reviews}
return render(request, 'randomtemplate.html', context)
# randomtemplate.html
{{ username }}
{{ latest_reviews }}