I've been advised that when it comes to updating a user I should use Django forms rather than rolling my own. As such, I've turned to Django forms but hit a bit of a wall.
A user in my system is defined, partly, as so:
#models.py
class Freelancer(AbstractBaseUser):
email = models.EmailField(primary_key=True)
first_name = models.CharField(max_length=128)
surname = models.CharField(max_length=128)
university = models.CharField(max_length=256)
verified = models.BooleanField(default=False)
biography = models.TextField(default="")
skills = models.ManyToManyField(Skill)
created_date = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
I have a URL:
#urls.py
url(r'^profile/$', views.Profile.as_view(), name="profile"),
And the view:
#views.py
class Profile(UpdateView):
model = Freelancer
fields = ['email']
template_name_suffix = '_update_form'
The problem is that I need to tell the server what Freelancer I want to update. I've tried adding (?P<pk>\d+)/ into the URL regex as I saw on a few tutorials but when I pass in the id of a Freelancer - as automatically created in the schema - it doesn't retrieve a Freelancer. Based on my model, what should I do?
I think it's a bad idea to use the email address as primary keys. What if a user changes their email address?
It might be a better idea to have unique=True for the email address, and let Django create the automatic primary key. Then including (?P<pk>\d+)/ in your url should work.
If you must use the email as the primary key, you need to change the regex from (?P<pk>\d+)/, which will only match digits, to something like
(?P<pk>[\w#.-]+)
The above might not catch all email addresses. I think Django contains a better character class, but I can't find it at the moment.
I think you are just doing it in a wrong way.
Here is what you need to do:
First of all I'd recommend you to add a pk to your model, as having email as a pk is a bad idea.
Create a url for update view
An example:
url(r'^profile/(?P<pk>[\d]+)/edit/$',
views.ProfileUpdateView.as_view(), name='edit_profile')
Create an UpdateView
An example:
class ProfileUpdateView(UpdateView):
model = Freelancer
fields = ['email']
template_name = "profiles/profile_edit.html"
Create a template for the form
An example:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update" />
</form>
Now you need to add this link wherever you want:
Edit
When you vist the url you will go to update page.
Related
I am having a tough time with following code.
{% if object.author == user.username %}
That code is not working neither giving error.
So I have articles app inside my django project. I want to make sure that if a user goes to their own post, then only they should be able to see delete and edit links (I will be placing them inside if block).
The Article model is as follows:
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
Here
{{user.username}}
{{object.author}}
both are valid django variables.
{{user.username}}
specifies username of current logged in user
{{object.author}}
specifies author of that particular post.
Please help me out to implement with comparison logic of both variables. I am using python 3.6, django 2.1 and django template language.
Your question would be easier to answer if you posted your models (and formatted your text correctly).
I presume that object.author is actually a ForeignKey to the User model. Therefore, you should compare directly with the user, not with the username attribute of the user:
{% if object.author == user %}
I don't know if the title is clear. It's quite difficult for me to explain it in simple way because the problem is not that simple and I'm not a very good English speaker. Every suggestion for improving a title are welcome.
So, let's go to the actual problem... In my application people can join different groups. Currently, I'm creating invitation system for this purpose, so user can send an invitation to another user. In a group view, I have a list of users which are not connected with this group, which allowing group members to invite those people. So, when I'm going to the group view, I am passing it's Primary Key. To create database cell about the invitation I need a group's PK and users PK as well (I want to do it using another view, but I'm not sure it's the best solution).
My question is: How can I pass those two PKs to the new view where I will create group-user relation cell in a database?
models.py:
class Group(models.Model):
name = models.CharField(max_length=500)
members = models.ManyToManyField(User, blank=True, related_name="member")
invitations = models.ManyToManyField(User, blank=True, related_name="invitations")
views.py:
def not_yet_members_list_view(request, pk):
group = Group.objects.get(pk=pk)
not_yet_members = User.objects.all() #doesn't matter
args = {'group': group, 'not_yet_members': not_yet_members}
return render(request, 'groups/show_members.html', args)
# Here is my problem (this code is a simplified version of what I want to achieve)
def invite_user_view(request, group_pk, user_pk):
invite_user(group_pk, user_pk)
return render(request, 'groups/show_members.html')
urls.py:
url(r'^not_yet_members_list/(?P<pk>\d+)/$', views.not_yet_members_list, name='not_yet_members_list'),
template.html:
{% for user in not_yet_members %}
<!-- ??? -->{{ user }}Invite
{% endfor %}
in the view from where you need to pass the group and user
request.session['group_pk'] = group_pk
request.session['user_pk']= user_pk
in the view where you need to access the data
group_pk = request.session['group_pk']
user_pk = request.session['user_pk']
then
invite_user(group_pk, user_pk)
after successful sending invitation
del request.session['group_pk']
del request.session['user_pk']
request.session.modified = True
Thank you very much for taking your time.
Previously, I posted this question, How to Get Unread Posts for Users.
The problem was: I cannot filter out which article one user has not read while this article has already been read by another user.
I figured out why I cannot do that---- because I have data that I wrote into the database without using Django although I set the reading default for each post to False---- there is simply no record.
Then, I manually set one article to unread to a user in the Admin, everything works, because now in the database there is one record stating that this certain article has not been read by this user.
The problem now is:
How do I set "unread" for every existing article that I have in the database for all existing users?
And how can articles stay unread for every new user unless the new user actually read it?
For your convenience, I copied the codes to here.
My model:
class Posts(models.Model):
title = models.CharField(max_length=255)
content_url = models.URLField(unique=True)
content = models.CharField(max_length=255)
post_date = models.DateField(default="2999-12-12")
Another
class readstatus(models.Model):
reading_status = models.BooleanField(default=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
article = models.ForeignKey(Posts, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
My View:
class DailyReading(ListView):
template_name = 'reading.html'
context_object_name = "data"
paginate_by = 20
def get_queryset(self):
if self.kwargs['status'] == "read":
queryset = piaoyou.objects.filter(readstatus__reading_status=True,readstatus__user=self.request.user)
return queryset
else:
queryset= Posts.objects.filter(readstatus__reading_status=False,readstatus__user=self.request.user)
return queryset
My Template:
{% for info in data %}
<quoteblock>
<ul>
<li><a href="{{ info.get_absolute_url }}">{{ info.title }}
<footnote></footnote>
</a>{{ info.post_date }}</li>
<footnote>{{ info.get_abstract_content }}</footnote>
</ul>
</quoteblock>
{% endfor %}
OMG, I just figured out how to do this.
For an article that has been read by the requesting user, we can just pass queryset = Post.objects.filter(readstatus__reading_status=True, readstatus__user=self.request.user)
For an article that has not been read by the requesting user yet, we can pass Posts.objects.all() into the template.
Then in the template:
We need {% if instance.readstatus_set.all %} this line to make things work. Assume there is no data about whether this requesting user has read the article, the instance should not have readstatus_set.all, which means the user has not read the article yet. Once checking this if condition, we can carry out to check other conditions in the loop.
I am a newbie to Django and could not find similar questions after searching on google/SO.
I've a model named Questions, which has multiple(2-4) choices and defined as below:
class Question(models.Model):
name = models.CharField(max_length=128)
class Choice(models.Model):
name = models.CharField(max_length=256)
is_correct = models.BooleanField(default=False)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
Of the multiple choices only one is correct.
What I want to do: In just one page, user could submit a question together with multiple choices, here is a draft of UI:
My first question: I've defined ModelForm but don't know how to add "choices" field to QuestionForm:
class QuestionForm(ModelForm):
name = forms.CharField(max_length=128)
description = forms.CharField(max_length=256)
class Meta:
model = Question
fields = ['name', 'description']
class ChoiceForm(ModelForm):
name = forms.CharField(max_length=256)
is_correct = forms.BooleanField()
class Meta:
model = Choice
fields = ['name', 'is_correct']
Is it possible to use ModelForm the render the above HTML page besides writing it manually?
My second question: If use clicks "Submit" button, I use AJAX to send json data to backend server, here is an example of form data:
name:question1
choices[][name]:choice1
choices[][is_correct]:1
choices[][name]:choice2
choices[][is_correct]:0
And this is my code handling the request:
form = QuestionForm(request.POST)
if form.is_valid():
question = form.save()
How to parse choices from the request?
How could I parse data of multiple choices part from the POST request?
Again, I'm a newbie to Django and any answers/suggestions is highly appreciated.
To create forms for models which have a OneToMany relation I would recommend you to use Django's inline formsets: https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#inline-formsets
It's a really simple and elegant way to create forms for related models.
To parse the choices, the user entered you could just override the clean method of your form. In this the user content is usually checked and prepared for storing it to the database. https://docs.djangoproject.com/en/1.8/ref/forms/validation/#form-field-default-cleaning
So cleaning could look like this:
class QuestionForm(ModelForm):
...
def clean(self):
cleaned_data = super(QuestionForm, self).clean()
if cleaned_data['choice_name'].startswith('Something'):
raise forms.ValidationError(
"Choice names cannot start with 'Something'!"
)
You models seems to be correct, in order to be able to add mutiple choices in your template you need a formset. In addition you can put a formset and a form inside the same html form in a template and have them be validated individually. Each one only cares about the POST data relevant to them. Something like:
template.html
<form method="post" action="">
{% csrf_token %}
{{ choices_formset.management_form }} <!-- used by django to manage formsets -->
{{ question_form.as_p }}
{% for form in choices_formset %}
{{ form.as_p }}
{% endfor %}
<button type='submit'>Submit</button>
</form>
views.py
from django.db import IntegrityError, transaction
from django.shortcuts import redirect
from django.forms.formsets import formset_factory
from django.core.urlresolvers import reverse
def new_question(request):
ChoicesFormset = formset_factory(ChoicesForm)
if request.method == 'POST':
question_form = QuestionForm(request.POST)
choices_formset = ChoicesFormset(request.POST)
if question_form.is_valid():
question = Question(**question_form.cleaned_data)
if choices_formset.is_valid():
question.save()
new_choice_list = list()
append_choice = new_choice_list.append
for form in choices_formset:
form.cleaned_data.update({'question': question})
append_choice(Choice(**form.cleaned_data))
try:
with transaction.atomic():
Choice.objects.bulk_create(new_choice_list)
except IntegrityError as e:
raise IntegrityError
return redirect(reverse('question-detail-view', kwargs={'id': question.id}))
def question_detail(request, id):
question_list = Question.objects.get(id=id)
return render(request, 'question_detail.html', {'question_list': question_list})
urls.py
url(r'^question/$', new_question, name='new-question-view'),
url(r'^question/(?P<id>\d+)/$', question_detail, name='question-detail-view'),
If you want to use rather Ajax submission rather than django form sumbission check this tutoriel.
I am creating a webpage that is going to be used as an interface for a numerical model (controlled by a python wrapper). The idea is that the user can input parameters into a form on the page, which creates an object with all the necessary information to run the numerical model. This is my forms.py
from django import forms
from models import ChemRun
class ChemRunForm(forms.ModelForm):
class Meta:
model = ChemRun
fields = ('owner', 'title', 'times_max','temperature_min', 'temperature_max')
my models.py
from django.db import models
from django.utils import timezone
class ChemRun(models.Model):
owner = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
created_date = models.DateTimeField(default=timezone.now)
times_max = models.DecimalField(max_digits=99, decimal_places=20, null=True)
temperature_min = models.DecimalField(max_digits=99, decimal_places=20, null=True)
temperature_max = models.DecimalField(max_digits=99, decimal_places=20, null=True)
def __unicode__(self):
return self.title
and the HTML code for the form to start a new model
<header>
<h2>Start a new model</h2>
</header>
<section>
<form action='/chemrun/create/' method='post'>{% csrf_token %}
<table>
{{form.as_table}}
</table>
<input type="submit" name="submit" value="New run">
</form>
</section>
Now to my first question:
How do I catch this object which contains all the model parameters and put it into a queue from which these objects are sent to the numerical model, and I want it to be able to handle multiple cores (e.g. I can specify that X of these models are running simultaneously). How would I handle this?
Second question:
Afterwards this numerical code will create a SQLite database with the results. How can I make this webapp be alerted when models are finish and then send an email to a user to let them know their data is ready?
If you can, please explain the steps, since I am still a bit of a newbie on Django, and I prefer to understand what I am doing and why :)
Many thanks for the help!