how to stop create view if already created django - django

please help me in making this application in django project
Here is models.py file code
from django.db import models
from bio.models import Profile
class Question(models.Model):
name = models.TextField(max_length=500)
def __str__(self):
return self.name
class Answer(models.Model):
question = models.ForeignKey(Question, related_name='question', on_delete=models.CASCADE)
profile = models.ForeignKey(Profile, related_name='profile', on_delete=models.CASCADE)
text = models.TextField(max_length=400)
created_on = models.DateTimeField(auto_now_add=True,null=True)
def __str__(self):
return "{0} on {1}".format(self.question, self.profile)
class Meta:
db_table = 'answer'
constraints = [
models.UniqueConstraint(fields=['profile', 'text', 'question'], name='unique answer')
]
here is views.py file code
class DetailViewMixin(object):
details_model = None
context_detail_object_name = None
def get_context_data(self, **kwargs):
context = super(DetailViewMixin, self).get_context_data(**kwargs)
context[self.context_detail_object_name] = self.get_detail_object()
return context
def get_detail_object(self):
return self.details_model._default_manager.get(pk=self.kwargs['pk'])
class AnswerCreate(DetailViewMixin, CreateView):
details_model = Question
context_detail_object_name = 'question'
model = Answer
form_class = NewAnswerForm
template_name = "qna/answer.html"
success_url = reverse_lazy('qna:list')
def form_valid(self, form):
form.instance.profile_id = self.kwargs.get('pk')
form.instance.question_id = self.kwargs.get('pk')
return super().form_valid(form)
here is my forms.py code
from django import forms
from .models import Answer
class NewAnswerForm(forms.ModelForm):
class Meta:
model = Answer
fields = ['text',]
def clean(self):
try:
Answer.objects.get(text=self.cleaned_data['text'].lower())
raise forms.ValidationError('Answer exists!')
except Answer.DoesNotExist:
pass
return self.cleaned_data
where am I going wrong????
I want that if user answers one question then he couldn't answer it again
how can i do form validation if object is already created

Add a UniqueConstraint to Answer so no combination of Question and Profile can be repeated:
https://docs.djangoproject.com/en/3.1/ref/models/constraints/#django.db.models.UniqueConstraint

Related

How to assign model form field to a current logged in user in Django's class based views

I am trying to save a form with the current logged in user's username, but the error "Cannot assign "'Neshno_Games2'": "League.host" must be a "Manager" instance." occurs
Views.py
class CreateLeaguesView(generic.CreateView):
model = League
template_name = "leagues/create-league.html"
form_class = LeaguesCreationForm
success_url = "/leagues/leagues"
def get_context_data(self, **kwargs):
context = super().get_context_data( **kwargs)
context['leagues'] = League.objects.all()
return context
def form_valid(self, form):
manager = self.request.user.username
League.objects.create(
host = manager,
)
return super(CreateLeaguesView, self).form_valid(form)
Model.py
class League(models.Model):
name = models.CharField(max_length=30)
no_players = models.IntegerField(default=20)
start_date = models.DateField(blank=False, null=False)
end_date = models.DateField(blank=False, null=False)
prize = models.CharField(max_length=300)
host = models.ForeignKey(Manager, on_delete=models.CASCADE)
def __str__(self):
return self.name
forms.py
class LeaguesCreationForm(forms.ModelForm):
class Meta:
model = League
fields = (
"name",
"no_players",
"start_date",
"end_date",
"prize",
)
You can try like this:
class CreateLeaguesView(generic.CreateView):
model = League
def form_valid(self, form):
form.instance.host= self.request.user.manager # accessing one to one data
return super().form_valid(form)
More information can be found here in this documentation: https://docs.djangoproject.com/en/4.0/topics/db/examples/one_to_one/

how to get tags from user in form and save it to database in django

I have a form that gets some fields and tags from users and save the user input data in database:
By the way I am using taggit
this is my model:
from taggit.managers import TaggableManager
class Question(models.Model):
title = models.CharField(max_length=500)
name = models.CharField(max_length=50, default=None)
slug = models.SlugField(max_length=500, unique_for_date='created', allow_unicode=True)
body = models.TextField(max_length=2000)
created = models.DateTimeField(auto_now_add=True)
tags = TaggableManager()
def get_absolute_url(self):
return reverse("questions:question_detail", args=[self.created.year, self.created.month, self.created.day, self.slug])
def __str__(self):
return self.title
and here is my view:
def question_form(request):
new_question = None
if request.method == 'POST':
question_form = QuestionForm(data=request.POST)
if question_form.is_valid():
new_question = question_form.save(commit=False)
new_question.slug = slugify(new_question.title)
new_question.save()
question_form.save_m2m()
else:
question_form = QuestionForm()
return render(request,
'questions/que/form.html',
{'question_form':question_form, 'new_question':new_question})
and my form.py is like this:
from taggit.forms import TagField
class QuestionForm(ModelForm):
class Meta:
model = Question
fields = ('name', 'title', 'body',)
tags = TagField()
my problem is when user enters the tags and other fields everything is saved in database except the tags! Can anyone help me?

How to reference a slug from a different model in get_success_url?

Setup
I have two models in my app. One is for a Journal and the other one is for entries to that journal. I wrote a CreateView class that will allow user to create a Journal entry for any Journal id currently located in. Ideally I want the class to "refresh" with the updated entry or in other words the get_success_url should lead the page we are currently located at.
views.py
class ToJournalEntriesList(LoginRequiredMixin, CreateView):
model = to_journal_entry
template_name = 'to_journals/to_journal_entries_list.html'
fields = ('body',)
def get_success_url(self):
return reverse('to-journals', kwargs={'slug':self.object.slug})
def form_valid(self, form):
current_journal = to_journal.objects.get(journal_user=self.request.user, slug=self.kwargs['slug'])
form.instance.journal_user = self.request.user
form.instance.journal_name = current_journal
return super(ToJournalEntriesList, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(ToJournalEntriesList, self).get_context_data(**kwargs)
context['to_journal_entries'] = to_journal_entry.objects.all()
return context
models.py
class to_journal(models.Model):
journal_name = models.CharField(max_length = 40)
slug = AutoSlugField(populate_from='journal_name')
date_created = models.DateTimeField(auto_now_add=True)
journal_user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,)
def __str__(self):
return str(self.journal_user) + " " + self.journal_name
def get_absolute_url(self):
return reverse('to-journals')
class to_journal_entry(models.Model):
body = models.TextField()
entry_date = models.DateTimeField(auto_now_add=True)
journal_name = models.ForeignKey(to_journal, on_delete=models.CASCADE,)
journal_user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE,)
def __str__(self):
return str(self.journal_name) + " " + str(self.entry_date)
def get_absolute_url(self):
return reverse('to-journal-entries', args=(self.slug))
urls.py
urlpatterns = [
path('', CreateToJournal.as_view(), name='to-journals'),
path('<slug:slug>', ToJournalEntriesList.as_view(), name='to-journal-entries'),
]
Error
With the current setup that I have I get:
Which makes sense, because the to_journal_entry model does not have that that field.
Question
I am sure both my get_success_url() in views.py and get_absolute_url() in models.py are done incorrectly, but I could not find a good explanation of how those work. How should I set them up to achieve desired result? Thanks a ton in advance!
I appreciate everyone taking a look. Best, Rasul.
You can just follow the relationship:
def get_success_url(self):
return reverse('to-journals', kwargs={'slug': self.object.journal_name.slug})
Your self.object is a to_journal_entry. You probably want to use the to_journal, you can do that by obtaining the journal_name:
class ToJournalEntriesList(LoginRequiredMixin, CreateView):
model = to_journal_entry
template_name = 'to_journals/to_journal_entries_list.html'
fields = ('body',)
def get_success_url(self):
return reverse('to-journals', kwargs={ 'slug': self.object.journal_name.slug })
Note: usually the names of the models are written in PerlCase, so JournalEntry instead of to_journal_entry.

Django: Change Choice selection from FK in a Form linked to an UpdateView

The Model flow Topic -> Section -> Article.
I am building an Update View for my FAQ project to update already created Articles. I want the Form to provide a selection of Sections based on the Topic the Article was created under. As I already have the Articles PK passed in through the URL I was hoping to use it to walk back up to the Topic when creating my filter. I am receiving an object has no attribute ‘section’ error when the template is attempting to render the form on line self.fields['section'].queryset = Section.objects.filter(topic_id=self.section.topic.id) in the UpdateAriticleForm. I need help to figure out my query filter.
The URL:
url(r'^ironfaq/article/update/(?P<pk>\d+)/$', ArticleUpdateView.as_view()),
The Form:
from django import forms
from .models import Topic, Section, Article
class CreateArticleForm(forms.ModelForm):
section = forms.ModelChoiceField(queryset=Section.objects.none())
def __init__(self, *args, **kwargs):
topic_pk = kwargs.pop('topic_pk')
super(CreateArticleForm, self).__init__(*args, **kwargs)
self.fields['section'].queryset = Section.objects.filter(topic_id=topic_pk)
class Meta:
model = Article
widgets = {
'answer': forms.Textarea(attrs={'data-provide': 'markdown', 'data-iconlibrary': 'fa'}),
}
fields = ('title','section','answer')
class UpdateArticleForm(forms.ModelForm):
section = forms.ModelChoiceField(queryset=Section.objects.none())
def __init__(self, *args, **kwargs):
super(UpdateArticleForm, self).__init__(*args, **kwargs)
self.fields['section'].queryset = Section.objects.filter(topic_id=self.section.topic.id)
class Meta:
model = Article
widgets = {
'answer': forms.Textarea(attrs={'data-provide': 'markdown', 'data-iconlibrary': 'fa'}),
}
fields = ('title','section','answer')
The View:
class ArticleUpdateView(UpdateView):
model = Article
form_class = UpdateArticleForm
template_name = "faq/form_create.html"
def form_valid(self, form):
article = form.save(commit=False)
article.activity_user = self.request.user.username
article.activity_date = datetime.datetime.now()
article.save()
self.success_url = "/ironfaq/%s/%s/%d" % (article.section.topic.slug,article.section.slug,article.id)
return super(ArticleUpdateView,self).form_valid(form)
The Models:
class Topic(Audit):
name = models.CharField(max_length=255)
icon = models.CharField(max_length=25,blank=True,null=True)
sort = models.SmallIntegerField()
slug = models.SlugField()
class Meta:
verbose_name_plural = "topics"
def __str__(self):
return self.name
class Section(Audit):
name = models.CharField(max_length=255)
sort = models.SmallIntegerField()
slug = models.SlugField()
topic = models.ForeignKey(Topic,on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "sections"
def __str__(self):
return self.name
class Article(Audit):
title = models.CharField(max_length=255)
sort = models.SmallIntegerField()
slug = models.SlugField()
section = models.ForeignKey(Section,on_delete=models.CASCADE)
answer = models.TextField()
vote_up = models.IntegerField(default=0)
vote_down = models.IntegerField(default=0)
view_count = models.IntegerField(default=0)
class Meta:
verbose_name_plural = "articles"
def __str__(self):
return self.title
The answer to the this issue was not passing 'pk' as a argument to the form and to add get_form_kwargs to the view to enable the form to see the 'pk' passed in the URL.
Form:
class UpdateArticleForm(forms.ModelForm):
section = forms.ModelChoiceField(queryset=Article.objects.none())
def __init__(self, pk, *args, **kwargs):
super(UpdateArticleForm, self).__init__(*args, **kwargs)
self.fields['section'].queryset = Section.objects.filter(topic_id__exact=Article.objects.filter(id=pk).first().section.topic.id)
View:
class ArticleUpdateView(UpdateView):
model = Article
form_class = UpdateArticleForm
template_name = "faq/form_create.html"
def get_form_kwargs(self):
kwargs = super(ArticleUpdateView,self).get_form_kwargs()
kwargs.update(self.kwargs)
return kwargs
def form_valid(self, form):
article = form.save(commit=False)
article.activity_user = self.request.user.username
article.activity_date = datetime.datetime.now()
article.save()
self.success_url = "/ironfaq/%s/%s/%d" % (article.section.topic.slug,article.section.slug,article.id)
return super(ArticleUpdateView,self).form_valid(form)

Django formsets

I'm making a survey site with django. I am pretty newbie with django so I apologize in advance if I can not explain well. My question focuses on the following models:
class SurveyType(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
class Question(models.Model):
ANSWERTYPE_CHOICES = (
(u'T', u'Text'),
(u'R', u'Range'),
(u'M', u'Media'),
)
question = models.CharField(max_length=200)
surveytype = models.ForeignKey(SurveyType)
answertype = models.CharField(max_length=1, choices=ANSWERTYPE_CHOICES)
order = models.IntegerField(default=0)
def __unicode__(self):
return self.question
class Survey(models.Model):
course = models.ForeignKey(Course)
surveytype = models.ForeignKey(SurveyType)
def __unicode__(self):
return u"%s %s" % (self.course, self.surveytype)
class Answer(models.Model):
answer = models.CharField(max_length=400)
survey = models.ForeignKey(Survey)
question = models.ForeignKey(Question)
def __unicode__(self):
return self.answer
Django receives survey id. With the survey id it gets the surveytype and shows questions that must be displayed.
def survey(request, survey_id):
survey_data = get_object_or_404(Survey, pk=survey_id)
survey_type = survey_data.surveytype
questions = Question.objects.all().filter(surveytype = survey_type).order_by('order')
I have read the django documentation about formsets but I don't understand what I have to write in forms.py, so I can't call the form in views.py to render de form in the template that shows the questions and write the answers in the answer model.
Thanks in advance and sorry for my english.
Solved using modelforms and a foor loop.
Models.py
class Question(models.Model):
question = models.CharField(max_length=200)
surveytype = models.ForeignKey(SurveyType)
answertype = models.ForeignKey(ContentType,
limit_choices_to = Q(name='text answer', app_label='surveys')| \
Q(name='media answer', app_label='surveys')| \
Q(name='range answer', app_label='surveys'))
class RangeAnswer(models.Model):
answer = models.IntegerField(max_length=1, choices=CHOICES_RANGE, default=0)
def __unicode__(self):
return u'%s'%(self.answer)
class TextAnswer(models.Model):
answer= models.CharField(max_length=200)
def __unicode__(self):
return u'%s'%(self.answer)
class MediaAnswer(models.Model):
answer= models.ForeignKey(Media)
def __unicode__(self):
return u'%s'%(self.answer)
Forms.py
class RangeAnswerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(RangeAnswerForm, self).__init__(*args, **kwargs)
self.fields['answer'].label = "Mi valoración"
class Meta:
model = RangeAnswer
widgets = {
'answer': forms.RadioSelect(renderer=RadioRenderer)
}
RangeAnswer.form = RangeAnswerForm
class MediaAnswerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MediaAnswerForm, self).__init__(*args, **kwargs)
self.fields['answer'].label = "Medio"
class Meta:
model = MediaAnswer
MediaAnswer.form= MediaAnswerForm
class TextAnswerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(TextAnswerForm, self).__init__(*args, **kwargs)
self.fields['answer'].label = "Respuesta"
class Meta:
model = TextAnswer
TextAnswer.form = TextAnswerForm
Views.py
for q in questions :
q.form = q.answertype.model_class().form(prefix="%s"%q.id)
Have you import the form to your views.py?
After that you just have to create a view that will pass the form to a template.
For example in the views.py
def your_form(request):
form = RegisterForm()
return render_to_response('your_template.html', {'form': form}, RequestContext(request))
and then in your template you can render the form simply by writing
{{ form }}