Django Rest Framework Hyperlinked Fields Understanding - django

I can't seem to grasp the difference between HyperlinkedIdentity and HyperlinkedRelated Fields. I have a few questions that I can't seem to find the answers to online.
What is the actual difference? When would I want to use one vs. the other.
My next question is say I have 2 models, Project and Task.
A Task has a ForeignKey to Project. If I wanted the Project to hyperlink to the tasks within it, which Hyperlink field would I put in the ProjectSerializer? And what field would I put in the TaskSerializer to complement the ProjectSerializer assuming I wanted the tasks to be able to hyperlink back to the Project they are related to?
What is the difference between using the hyperlinked fields vs. just using regular nested serializers? When using hyperlinked fields, can I still filter by pk/id?
Last, What if a model had two hyperlinked relations in the serializer? From what I understand it creates a url field for each hyperlink, would it create two url fields in this case?
Thanks for any clarification you can offer, it will be a huge help towards cementing my understanding on the subject and allowing me to complete my API for my project.

What is the actual difference? When would I want to use one vs. the other.
HyperlinkedIdentityField is an hyperlink field for the current object itself while HyperlinkedRelatedField represent an hyperlink to other instances.
A Task has a ForeignKey to Project. If I wanted the Project to hyperlink to the tasks within it, which Hyperlink field would I put in the ProjectSerializer? And what field would I put in the TaskSerializer to complement the ProjectSerializer assuming I wanted the tasks to be able to hyperlink back to the Project they are related to?
HyperlinkedRelatedField is what you're looking for.
What is the difference between using the hyperlinked fields vs. just using regular nested serializers?
Hyperlinks can be browsed independently from the original resource. Handy if one of them belongs to another system. For example, you'll likely want to use hyperlink to tweets rather than let your server fetch them and them return them nested. Hyperlinks also allows the client to deal with its own caching rather than sending back all the data. Could be handy in case of fetching a list of items that nest the same user.
On the other hand, hyperlinks increase the network request count because it needs to fetch more data.
When using hyperlinked fields, can I still filter by pk/id?
Not sure what you mean here.
What if a model had two hyperlinked relations in the serializer? From what I understand it creates a url field for each hyperlink, would it create two url fields in this case?
Correct. hyperlinked relation are just a representation of a relation. It provides an hyperlink (an uri) to fetch the associated object.
This is useful because you won't need to know the pattern to fetch an object from the id: with a PrimaryKeyRelatedField you'll get the id but are missing the url to fetch the associated object.
This also allows the server to manage its own uri space without the need of updating the clients.
Hope this will help.

Related

How to implement the add/edit links on a field in the admin change page that does not have an expressed FK relationship in the model?

I have a Django 3.x web site. There are 3 models, among others, Document, MetaData, MetaDataValue. The MetaDataValue model has a foreign key relationship to the MetaData model.
In a simple world, there would be a foreign key relationship from MetaData to Document. Then the DocumentAdmin would display the MetaData field as a dropdown, filled with the appropriate MetaDataValues. There would also be edit/add (pencil/plus) links next to the dropdown to allow the user to edit/add the MetaDataValue for that MetaData object.
However, one of the requirements for the project was not to define which, or how many, MetaData objects would be associated with a particular Document type until run time. Those associations are through another set of models. Therefore, the Document admin change page adds the different MetaData fields to the change admin page at run time, by looking into the database for which MetaData fields are associated with this type of Document, and then adding them to the fieldset through the get_fieldsets method.
The implication of this design is that one cannot edit/add values to a particular MetaData field on the Document admin change page, because, I assume, Django lost the underlying foreign key relationship between the Document and MetaData models because the fieldset is generated in the admin's get_fieldsets method.
I could add pages of code to show how the MetaData fields are generated at run time, but I don't think that would make the description any clearer. I have looked at the page source and fieldsets generated for the "simple world" example described above above, and cannot see where Django is figuring out when to add the edit/change links to the drop down for a particular foreign key field.
My question, is how can I add the pencil and plus sign to these MetaData fields displayed in the Document admin change page, and give the user to option to add/edit the MetaDataValue for that particular MetaData object? I could just create some Ajax calls and do all the heavy lifting myself, bu I would prefer to leverage as much of the Django infrastructure as possible, and not reinvent more than I have to.
Thanks!
Mark
I found a solution using the RelatedFieldWidgetWrapper. I added this widget wrapper to all my selects that needed the green plus (add) and yellow pencil (edit).
There is too much code to post here, but here is the meat of it. My db table MetaData has the names of all the fields, and MetaDataValue has the values for each metadata field. The metadata is used to describe a document (text, video, image), but there are no FK relationships between the MetaData model and the Document model. The relationship between the metadata and the documents is contained in a JSON field in another table. The MetaData table also has what type of Django field is used for that metadata field. There is also another table that determines which metadata fields apply to which document type (image, text, video). For all the ModelChoiceFields, I add the field and the widget (Select wrapped in a RelatedFieldWidgetWrapper).
elif (metadata_names[i].field_type == MetaData.MODELCHOICEFIELD):
fields[metadata_names[i].name] = forms.ModelChoiceField(queryset=MetaDataValue.objects.filter(metadata_id=metadata_names[i].metadata_id).order_by('value'), required=False, label=metadata_names[i].label, help_text=metadata_names[i].help_text)
# add the green plus (add) and pencil (edit) links to each select field
fields[metadata_names[i].name].widget = RelatedFieldWidgetWrapper(fields[metadata_names[i].name].widget, MetaDataValue._meta.get_field('tag_value'), admin_site, can_add_related=True, can_change_related=True)
if 'documentType_id' in fields:
# Editing/add a new document type seems like a bad idea, as document type is used a lot in the processing logic
fields['documentType_id'].widget.can_add_related = False
fields['documentType_id'].widget.can_change_related = False
The hard part was getting the right arguments for the RelatedFieldWidgetWrapper. The documentation is a little sparse on that widget, because, I think, it was an early part of the admin, but much of the Django code has changed since it was first implemented, so a lot of ways this wrapper was used in the past (ie stack overflow posts) has been deprecated. I just looked at the source, and tried what seemed to be appropriate until it worked. Finally, these articles helped a lot:
RelatedFieldWidgetWrapper
More RelatedFieldWidgetWrapper – My Very Own Popup
How can I remove the add and change buttons from a TabularInline admin field?

How to check duplicate posts when submitting a new post in Django admin?

I have coworkers to upload posts through Django admin. The problem is they keep making duplicate posts as we've been covering a lot of posts. Is there a way to find out if a post already exists when typing a certain column or submitting?
I searched about that, but didn't get any useful information.
Your business case seems to be a text that is duplicate if it is case sensitive equal.
On a DB and Django Model level you assure unique entries by adding unique:
class MyModel(Model):
my_field = TextField(unique=True)
To check during input you need JavaScript in the client and an AJAX endpoint on the Django server side. It's actually an Autocomplete/Autosuggest functionality for that field. There are several packages that might help you with that. Out of the box, the Django Admin does not support this.

Creating a Django Rest Api to Store Values

I have a python parser who creates two python lists, first one contains some IDs and the second one contains ip:port information which corresponds to those ID's. I need to create a django rest api to send these values and store them. I tried to read django documentation but I still don't know what to do, where to start. Can anyone help me? Thanks in advance.
The question is not easy to answer, although I can show you the right direction.
Django uses the Model object to interact with database. Therefore you should create one model with two fields. The first one is ID (although read the documentation carefully, Django can create the ID automatically for you) and the second one should be a String (or really object of your choice) to store IP/Port information. For information about models, visit the following page:
https://docs.djangoproject.com/en/2.1/topics/db/models/
To submit your information to Django back-end, POST request should be used. What is POST request is beyond the scope of this comment, so I will just expect that you know what it is. Open your urls.py file and make an endpoint for this particular request. More information can be found here: https://docs.djangoproject.com/en/2.1/topics/http/urls/.
To create a form for user, Django offers great object called Form. You need to create one in the forms.py file. To give you an example:
from yourapp.models import YourModelObject
class InformationForm(forms.ModelForm):
class Meta:
model = YourModelObject
fields = ('id', 'ipportField')
To read more about forms, check the following doc: https://docs.djangoproject.com/en/2.1/topics/forms/

Accessing url of ImageField via values() method on django queryset

I have a data model in Django where I save photos uploaded by users. There's an attribute called image_file in the Photo model (of the type ImageField) where - among other things - the image's url is stored. I can successfully access this url with item.image_file.url in the template (and view) for instance.
However, I can't seem to be able to do the following in the view:
Photo.objects.filter(owner=user).order_by('-id').values('id','image_file.url')[:10]
I.e. For a particular user, I'm trying to get the 10 latest photo objects' image urls along with object ids. This gives me FieldError: Cannot resolve keyword 'image_file.url' into field. Shouldn't this have worked?
I understand I can retrieve the entire object and do the filtering in the template, but I felt it's more optimal to solely retrieve the fields I actually need instead of the full object.
p.s. it's a postgresql backend and the underlying Storage class has been over-ridden
The url is a property, not a value in the database (FileField code) which is why you can't get to it from values(). As far as I can see, you'd have to get the url value separately...
You might want to take a look at only() though. If you go that route, you should probably watch the SQL queries with something like Django Debug Toolbar. If the url property tries to retrieve a field that wasn't included in only(), it will likely make a separate SQL call.

Hidden select multiple items Django

I've got several forms in my django app that require support for attachments. Each form instance may have any number of attachments, including none. I want to present a jQuery based upload widget for managing these uploads, allowing the uploads to be processed asynchronously. The attachments are stored in their own model, so there is then a many-to-many from the attachments model to each model that requires attachments. When an attachment is sucessfully uploaded and processed, the view handling the upload will return the id in the attachments model, which will then be inserted into a hidden field on the form. I'm currently trying to decide how best to represent this in the form.
One method would be to simply have a single hidden input which takes a comma separated list of ids. This would then require quite a lot of manual processing and validation on submission, which I can't help feeling could be avoided.
Elsewhere, I've used a HiddenInput for a single value where I'm doing something similar and dynamically adding items to the related model in the form. I can't however see how I can extend this directly to a Many to Many from a simple Foreign Key.
Anyone able to suggest the best way to go about doing this?
Try to use formsets or model_formsets to create a form for creating/editing multiple objects, also you can use javascript to add forms dynamically in your browser.