I have a custom user model (CustomUsers) on one app called users, and then I have a model called Bookings from which I have created a ModelfForm called BookingsForm.
In the Bookings model (and ultimately the BookingsForm), I have a field called booking_author which has a ForeignKey inherited from the CustomUsers model.
Now I have been able to successfully call the booking_author field into my bookingscreate view and make it uneditable/read only as I had wanted. The issue now is that the field is displaying the id of the author instead of the name of the author. Is anyone able to help me resolve this?
views.py
#login_required
def bookingscreate(request):
bookings_form = BookingsForm(initial={'booking_author': request.user })
context = {
'bookings_form': bookings_form
}
return render(request, 'bookings_create.html', context)
There are multiple ways of getting the users name. To obtain the user name in this case you could use
request.user.get_full_name()
request.user.get_short_name()
Explanation:
request.user is the User object, and thus you have access to all user methods. If the above is not what you're looking for you could create a method in your user class and then call that method in this view.
Related
I am making a simple webapp with Django. A user can have a profile, and under that profile create a blog post.
For example:
"path('profile/<int:pk>/',profile, name='profile')"
Returns the URL
"http://127.0.0.1:8000/profile/1/"
A user can then write blog posts which have the name in the URL
Example:
path('profile/<int:pk>/blog/<str:name>',Blogs, name='Blogs'),
Returns the URL
"http://127.0.0.1:8000/profile/1/blog/HelloWOrld"
However, IF two different users both name their blogs the same exact name, i get a 'MultipleObjectsReturned' Error.
I thought that by having the user PK earlier in the URL it would ensure that it would be unique, even if two blogs were called the exact same thing.
Views.py
def Blog(request, pk, name):
blog = Restaurant.objects.get(name=name)
user = CustomUser.objects.get(pk=pk)
if not user.id == request.user.pk:
raise PermissionDenied()
else:
context = {
'user': user,
'blog': blog,
}
return render(request, 'blog/blogs.html',context)
IS there any way to work around this without using the PK of the blog as well?
And if anyone could explain why my logic was wrong and it wasn't working in the first place.
Thanks.
You need to make sure you get the blog of that name of that user. I don't know exactly how your blog models look, but it's going to be something like
user = CustomUser.objects.get(pk=pk)
blog = Restaurant.objects.get(name=name, user=user)
And on the model, use the 'unique_together' property to ensure that the combination of user and blog name are unique, otherwise these URLs aren't going to work. Having the name completely unique as in George's answer isn't necessary and would mean that users couldn't create blog posts with titles already made by another user.
You need to make name field unique, and use SlugField for this if you want to use clean url:
class Restaurant(models.Model):
name = models.CharField(unique=True, ...)
slug = models.SlugField(unique=True, ...)
...
I am creating an application in Django REST Fremework, in which the user can add an order.
I would like the serializer to set a reference to the user based on the token and complete the "Client" model field.
It's actually works with HiddenField, as shown in the documentation.
(Link: https://www.django-rest-framework.org/api-guide/fields/#hiddenfield)
class OrderSerializer(serializers.ModelSerializer):
client = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Order
fields = '__all__'
The problem is that when I fetch a single order or list of orders, Client field is of course hidden becouse of HiddenField type.
curl -X GET http://127.0.0.1:8000/api/orders/12
{
"id":12,
"name":"sprzatanie ogrodka",
"description":"dupa",
"price":"12.20",
"work_time_hours":2,
"work_time_minutes":50,
"workers_needed_num":3,
"coords_latitude":"-1.300000",
"coords_longitude":"1.100000",
"created_at":"2020-03-08T13:20:16.455289Z",
"finished_at":null,
"category":1,
"workers":[]
}
I would like the field to still capture reference to the logged in user, but at the same time to be visible when returning data from the API.
What serializers field type I need to use?
Thanks!
Going through the documentation i found: https://www.django-rest-framework.org/api-guide/validators/
Using a standard field with read_only=True, but that also includes a default=… argument. This field will be used in the serializer output representation, but cannot be set directly by the user.
this is what you need i think.
So whatever field type you have set in Model can be used with read_only=True
For example:
client = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
Hope this helps
I'm building a social network where user are supposed to be able to follow each other. So I define a class user with a field: ManyToMany to stock the users that follow this user. This is what I have done in my model.py:
followings = models.ManyToManyField('self', blank=True)
This is my view.py:
#login_required
def follow_test(request):
name = request.POST.get('name', '')
user_followed = Dater.objects.get(username=name)
current_user = Dater.objects.get(id=request.user.id)
print current_user.followings # display my_app.Dater.None
current_user.followings.add(user_followed)
print current_user.followings # display my_app.Dater.None
I retrieve correctly my users (current (The one who follow someone) and the followed one) but I can't add the followed user in the set followings of the current user. Can you see something I don't do properly in my view?
followings is a manager; to show the members of that relationship, you need to call .all() on it (or another manager/queryset method like order_by).
print current_user.followings.all()
According to the Django tutorial, you should access form fields using cleaned_data dictionary. I'm wondering why I can't access the properties of the form directly? My form validates just fine, but when I try to access it, Django complains that the object does not have the attribute. I added some code below that I hope will help diagnose the problem.
Form:
class CustomForm(forms.Form):
description = forms.CharField(widget = forms.TextInput(attrs = {'placeholder' : 'enter some text'}), label = "My form")
View:
def process_form(request):
if request.method != 'POST':
raise Http404
myForm = CustomForm(request.POST)
if not myForm.is_valid():
c = RequestContext(request)
return render_to_response('home/index.html', {'form' : myForm }, c)
# debug
print 'Description: ' + myForm.description # this does NOT work
# print 'Description: ' + myForm.cleaned_data['description'] # this does work
I get the following error: 'CustomForm' object has no attribute 'description'. Did I miss something in the docs that says I can't do that?
If your form is validated then you can access myForm cleaned_data:
print myForm.cleaned_data.get('description')
If you want to see why you cannot access myForm.description then you can see the data dictionary of your myForm:
print myForm.__dict__
The way you define fields using django.forms is just a convenient, declarative syntax; it's not really representative of what the final Form class, or an instance of it, looks like in terms of attributes.
Forms have a metaclass (without getting too deep into it, a metaclass is to declaring a class using the class keyword as an __init__ method is to creating an instance of a class using parentheses -- a hook to customise the object being created, which in the case of a metaclass, is a class!) which picks off Fields from the form class at definition time and adds them to a base_fields dict. When you instantiate a form, its base_fields are deep-copied to a fields attribute on the instance.
One point of confusion might be that you use . to access fields for display in templates -- what's actually happening there is that Django's template engine first attempts to use dictionary-style [] access to resolve property lookups and the base form class defines a __getitem__ method to take advantage of this, looking up the appropriate field from the form instance's fields dict and wrapping it with a BoundField, a wrapper which knows how to use the field and data from the form for displaying the field.
You can access the fields of a Form instance from its fields attribute.
myForm.fields['description']
And some property like label can be accessed like this:
myForm.fields['description'].label
Not sure how to display the value corresponding. Anybody having idea?
here is my reference
https://docs.djangoproject.com/en/dev/ref/forms/api/#accessing-the-fields-from-the-form
You can access your field trought dict.
form.__dict__["fields"]["description"]
In Django, how do I associate a Form with a Model so that data entered into the form are inserted into the database table associated with the Model? How do I save that user input to that database table?
For example:
class PhoneNumber(models.Model):
FirstName = models.CharField(max_length=30)
LastName = models.CharField(max_length=30)
PhoneNumber = models.CharField(max_length=20)
class PhoneNumber(forms.Form):
FirstName = forms.CharField(max_length=30)
LastName = forms.CharField(max_length=30)
PhoneNumber = forms.CharField(max_length=20)
I know there is a class for creating a form from the the model, but even there I'm unclear on how the data actually gets to the database. And I'd like to understand the inner workings before I move on to the time-savers. If there is a simple example of how this works in the docs, I've missed it.
Thanks.
UPDATED:
To be clear -- I do know about the ModelForm tool, I'm trying to figure out how to do this without that -- in part so I can better understand what it's doing in the first place.
ANSWERED:
With the help of the anwers, I arrived at this solution:
Form definition:
class ThisForm(forms.Form)
[various Field assignments]
model = ThisModel()
Code in views to save entered data to database:
if request_method == 'POST':
form = ThisForm(request.POST)
if form.is_valid():
for key, value in form.cleaned_data.items():
setattr(form.model, key, value)
form.model.save(form.model)
After this the data entered in the browser form was in the database table.
Note that the call of the model's save() method required passage of the model itself as an argument. I have no idea why.
CAVEAT: I'm a newbie. This succeeded in getting data from a browser to a database table, but God only knows what I've neglected or missed or outright broken along the way. ModelForm definitely seems like a much cleaner solution.
Back when I first used Forms and Models (without using ModelForm), what I remember doing was checking if the form was valid, which would set your cleaned data, manually moving the data from the form to the model (or whatever other processing you want to do), and then saving the model. As you can tell, this was extremely tedious when your form exactly (or even closely) matches your model. By using the ModelForm (since you said you weren't quite sure how it worked), when you save the ModelForm, it instantiates an object with the form data according to the model spec and then saves that model for you. So all-in-all, the flow of data goes from the HTML form, to the Django Form, to the Django Model, to the DB.
Some actual code for your questions:
To get the browser form data into the form object:
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
model.attr = form.cleaned_data['attr']
model.attr2 = form.cleaned_data['attr2']
model.save()
else:
form = SomeForm()
return render_to_response('page.html', {'form': form, })
In the template page you can do things like this with the form:
<form method="POST">
{{ form.as_p }}
<input type="submit"/>
</form>
That's just one example that I pulled from here.
I'm not sure which class do you mean. I know that there were a helper, something like form_for_model (don't really remember the exact name; that was way before 1.0 version was released). Right now I'd it that way:
import myproject.myapp.models as models
class PhoneNumberForm(forms.ModelForm):
class Meta:
model = models.PhoneNumber
To see the metaclass magic behind, you'd have to look into the code as there is a lot to explain :]. The constructor of the form can take instance argument. Passing it will make the form operate on an existing record rather than creating a new one. More info here.
I think ModelForm.save documentation should explain it. With its base class (Form) you would need to use the Form.cleaned_data() to get the field values and set them to appropriate Model fields "by hand". ModelForm does all that for you.
The Django documentation is pretty clear on this subject. However, here is a rough guide for you to get started: You can either override the form's save method or implement that functionality in the view.
if form.is_valid() # validation - first the fields, then the form itself is validated
form.save()
inside the form:
def save(self, *args, **kwargs):
foo = Foo()
foo.somefield = self.cleaned_data['somefield']
foo.otherfield = self.cleaned_data['otherfield']
...
return foo.save()