URL to redirect related model instance django - django

I have a 2 models with ForeignKey linked to each other
class Moc(models.Model):
title = models.CharField(max_length=128, blank=False)
scope = models.TextField(max_length=128, blank=False)
....
def __str__(self):
return self.title
class Verifier(models.Model):
moc = models.ForeignKey(Moc, related_name='verifiers' on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
approve = models.BooleanField(default=False). reject =
reject = models.BooleanField(default=False)
....
def __str__(self):
return str(self.id)
I have a respective forms, views and templates to create, update, delete records.
def verifier_signoff_view(request, pk):
verifier = Verifier.objects.get(pk=pk)
form = VerifierSignForm
if request.method == 'POST':
form = VerifierSignForm(request.POST, instance=verifier)
if form.is_valid():
form.save(commit=False)
if verifier.approve is True and verifier.reject is True:
return HttpResponseForbidden('You have either APPROVE or REJECT - operation not allowed!')
else:
form.save()
return redirect('verify_coorinate' pk=verifier.moc_id) # This is where I need help...
else:
return render(request, 'moc/verify_signoff.html', context={'verifier': verifier, 'form': form})
My urls.py
urlpatterns = [
....
....
path('moc-content/<int:pk>/verify-coordinate, views.verify_coordinate_view', name='verifiy_coordinate'),
....
....
]
What I want is that after I update verifier instance as per above view, I want to redirect back to moc instance rather than verifier instance, i.e. pass in url Moc instance pk instead of Verifier instance pk.
Any help please...

you probably forgot the comma:
redirect('verify_coorinate', pk=verifier.moc_id) # This is line, where you need help
more here:
https://docs.djangoproject.com/en/4.1/topics/http/shortcuts/#redirect
Please, try to use Django-GCBV. In your case it can be UpdateView or FormView with SingleObjectMixin
more here:
https://docs.djangoproject.com/en/4.1/ref/class-based-views/generic-editing/#django.views.generic.edit.UpdateView

Related

Django Formset: how to get the current user? (using django-extra-views)

I'm used to collecting the current logged in user in a CreateView and passing it to the form like so:
class MakeFantasyTeam(CreateView):
form_class = MakeFantasyTeamForm
[...]
def form_valid(self, form):
form.instance.team_manager = self.request.user
form.save()
return super(MakeFantasyTeam, self).form_valid(form)
However, this doesn't seem to work when using an InlineFormSetView as provided by django-extra-views. I get an error NOT NULL constraint failed: tournament_invite.invited_by_id and I'm not sure how to get the user.id passed on to the form.
My View:
class InvitePlayersView(InlineFormSetView):
template_name = 'invite_players.html'
model = Tournament
inline_model = Invite
form_class = InvitePlayerForm
pk_url_kwarg = 'tourney_id'
factory_kwargs = {'can_delete': False, 'extra': 1}
def formset_valid(self, formset):
tourney_id = self.kwargs['tourney_id']
formset.instance.invited_for = Tournament.objects.filter(id=tourney_id).get()
formset.instance.invited_by = self.request.user
formset.save()
return super(InvitePlayersView, self).formset_valid(formset)
def get_success_url(self):
return reverse('make_team', kwargs={'tourney_id': self.object.invited_for.id})
My Model:
class Invite(models.Model):
name = models.CharField(max_length=200, blank=True, null=True)
email = models.CharField(max_length=320, null=False, blank=False, validators=[EmailValidator],)
invited_by = models.ForeignKey(get_user_model(), on_delete=models.DO_NOTHING)
invited_for = models.ForeignKey(Tournament, on_delete=models.DO_NOTHING)
created_dt = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.email
def get_absolute_url(self):
return reverse('home')
My Form:
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = Invite
fields = ('name', 'email',)
Any tips or hints much appreciated!
Thank you,
Jon
Edit: Just to clarify what I'm trying to do here; I want a user to submit a formset. The data of that formset should be stored in the model, and the userid of the submitting user should also be stored in the model. I don't seem to be able to pass on the userid though.
I am not sure what you exactly want to do here, As per my understanding you want to use the currently logged in user's information. To do so you can append the user's info in the session dictionary. After that you can use the information in templates or in other views too.
In authentication view
def login(request):
#your necessary data
request.session['user_id']=The_user_id
request.session['user_name']=The_userName
To access data in the template
{% request.session.user_id %}
{% request.session.user_name %}
To access data in other views
def myview(request):
user_id= request.session['user_id']
user_name= request.session['user_name']

How to retrieve user selections from a previous form

I have several forms that take people through steps and below are the first two and the simplest ones and makes it easy to explain what i am having problem with.
The following two views are login required and contain one form on each. First view is the new_operator where the user fills out a single text input field. Second view is the new_asset where the user fills one text input field as the asset name and selects an operator from the a select/dropdown field. The question is how can i get the form to remember the operator name the user created in the previous form and make it as the default option? To be clear, i still want the user to select any other operator if they choose to do so but i want the option they just created to be the default. Thanks a lot in advance for the help.
First, here are the models:
class OperatorCompany(models.Model):
name = models.CharField(max_length=50, unique=True)
created_at = models.DateTimeField(default=timezone.now)
created_by = models.ForeignKey(User, related_name='operator_added_by', null=True, on_delete=models.SET_NULL)
class Meta:
verbose_name = "Operator Company"
verbose_name_plural = "Operator Companies"
def __str__(self):
return self.name
class AssetName(models.Model):
name = models.CharField(max_length=50, unique=True)
operator = models.ForeignKey(OperatorCompany, related_name='asset', on_delete=models.CASCADE)
created_at = models.DateTimeField(default=timezone.now)
created_by = models.ForeignKey(User, related_name='asset_added_by', null=True,
on_delete=models.SET_NULL)
class Meta:
verbose_name = "Asset"
verbose_name_plural = "Assets"
def __str__(self):
return self.name
views.py
def new_operator(request):
if request.method == 'POST':
form = NewOperatorForm(request.POST)
if form.is_valid():
newoperator = form.save(commit=False)
newoperator.created_by = request.user
newoperator.created_at = timezone.now()
newoperator.save()
return redirect('wellsurfer:new_asset')
else:
form = NewOperatorForm()
return render(request, 'wellsurfer/create_new_operator.html', {'create_operator': form})
def new_asset(request):
if request.method == 'POST':
form = NewAssetForm(request.POST)
if form.is_valid():
newasset = form.save(commit=False)
newasset.created_by = request.user
newasset.created_at = timezone.now()
newasset.save()
return redirect('wellsurfer:new_pad')
else:
form = NewAssetForm()
return render(request, 'wellsurfer/create_new_asset.html', {'create_asset': form})
and following are the forms.py without the init, clean functions and the widgets
class NewOperatorForm(forms.ModelForm):
class Meta:
model = OperatorCompany
fields = ('name',)
class NewAssetForm(forms.ModelForm):
class Meta:
model = AssetName
fields = ('name', 'operator')
To share data between multiple pages, you can use session variables. These are stored on the server and associated to clients according to the session cookie they communicate to the server at every request.
Typically, in the first view, you would add after save():
request.session['latest_created_operator_id'] = newoperator.id
to save in the session the operator id.
And in the second view, after the else,
operator_id = request.session.get('latest_created_operator_id', None)
operator = Operator.objects.filter(id=operator_id).first() # returns None if not found
form = NewAssetForm(initial={'operator': operator})
retrieves the operator and populates the form.
(That's untested code; you may need to edit a bit.)
At a glance, maybe something like this would work.
What you can do is add another URL in urls.py for new_asset which accepts a OperatorCompany id. I don't have your url config but it could be something like:
urls.py
path('wellsurfer/new_asset/<int:operator_id>', new_asset, name='wellsurfer:new_asset_operator')
view.py
def new_operator(request):
if request.method == 'POST':
form = NewOperatorForm(request.POST)
if form.is_valid():
newoperator = form.save(commit=False)
newoperator.created_by = request.user
newoperator.created_at = timezone.now()
newoperator.save()
return redirect('wellsurfer:new_asset', operator_id=newoperator.id)
else:
form = NewOperatorForm()
return render(request, 'wellsurfer/create_new_operator.html', {'create_operator': form})
def new_asset(request, operator_id=None):
if request.method == 'POST':
form = NewAssetForm(request.POST)
if form.is_valid():
newasset = form.save(commit=False)
newasset.created_by = request.user
newasset.created_at = timezone.now()
newasset.save()
return redirect('wellsurfer:new_pad')
else:
form = NewAssetForm()
if operator_id is not None:
operator_company = OperatorCompany.objects.get(pk=operator_id)
form.fields['operator'].initial = operator_company
return render(request, 'wellsurfer/create_new_asset.html', {'create_asset': form})

Django - display and saving in a simple form

This is a very beginner-orientated question but I've been stuck on this issue all day.
I would like to load the data for a specific record and be able to save it (Submit button in a template) but i'm still trying to understand instances and the save method.
models.py
class model_essays(models.Model):
user = models.ForeignKey(User, default='1', on_delete=models.CASCADE)
title = models.CharField(max_length=100, default='')
date_added = models.models.DateTimeField(auto_now_add=True)
body = models.TextField()
def __str__(self):
return self.title
I understand the id is created automatically
forms.py
class frm_essays (forms.ModelForm):
class Meta:
model = model_essays
fields = ['title', 'date_added', 'body']
urls.py
urlpatterns = [
path('essay/<int:pk>', views.views_essay),
]
views.py {stuck here}
#login_required
def views_essay(request, pk):
if request.method == 'POST':
updatedForm = essay_detail(request.POST, instance=request.? {I want the ID of the essay})
if u_form.is_valid():
updatedForm.save()
messages.success(request, f'this essay has been updated')
return redirect('essay_detail')
else:
updatedForm = frm_essays(instance=request.{as above})
context = {
'updatedForm': updatedForm
}
return render(request, 'essay_detail.html', context)
On the decorator - I haven't gotten around to only allowing the users to view their own created essays, this would be the next large hurdle but not the issue I'm asking about.
Unless I am mistaken you are looking for the same ID as the pk (primary key). You have that passed in as an argument to your function.
You just need to query the instance from the DB.
def views_essay(request, pk):
essay = model_essays.objects.get(pk=pk)
if request.method == 'POST':
updatedForm = essay_detail(request.POST, instance=essay)
...
Note: essay will be None if the query based on the pk does not find an match in the DB.

django - upload file to a specific folder

I have a userprofile that captures the username and the group the user is assigned to. I want the uploaded files to be saved under the group name folder. The folders already exit at the media root, the files shoud be routed to these folder
I solved the problem by the solution given. Now the username is shown as a dropdown list on the upload page. I want only the logged it username to be shown or exclude even showing it
models.py
class uploadmeta(models.Model):
path = models.ForeignKey(Metadataform, on_delete=models.CASCADE)
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, verbose_name='Username')
tar_gif = models.FileField(upload_to=nice_user_folder_upload, verbose_name="Dataset") # validators=[FileExtensionValidator(allowed_extensions=['tar', 'zip'])]
def __str__(self):
return self.request.user.username
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Group= models.CharField(max_length=500, choices=Group_choices, default='Please Select')
def __str__(self):
return self.user.username
view.py
def uploaddata(request):
if request.user.is_authenticated:
if request.method == 'POST':
form = uploadmetaform(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('file_list')
else:
form = uploadmetaform()
return render(request, 'uploaddata.html', {
'form': form
})
else:
return render(request, 'home.html')
forms.py
class uploadmetaform(forms.ModelForm):
count = Metadataform.objects.all().latest('id').id #To know the id of latest object
data = Metadataform.objects.all().filter(id=count) #return the queryset with only latest object
path = forms.ModelChoiceField(queryset=data)
def __init__(self, *args, **kwargs):
super(uploadmetaform, self).__init__(*args, **kwargs)
count = Metadataform.objects.all().latest('id').id
data = Metadataform.objects.all().filter(id=count)
self.fields['path'] = forms.ModelChoiceField(queryset=data)
class Meta:
model = uploadmeta
fields = ['path', 'user_profile','tar_gif',]
You can use the upload_to argument in the FileField.
It accept a string representing the path where you want to store the file or you can pass in a function which let you add more details.
More info from the doc: https://docs.djangoproject.com/fr/2.2/ref/models/fields/#django.db.models.FileField.upload_to
You may need to add a foreign key form uploadmeta to UserProfile like :
user_profile = models.ForeignKey(UserProfile, on_delete=models.PROTECT)
Then you can use the following
def nice_user_folder_upload(instance, filename):
extension = filename.split(".")[-1]
return (
f"your_already_definied_folder/{instance.user_profile.group}/{file}.{extension}"
)
Then use it in uploadmeta FileField
doc = models.FileField(upload_to=nice_user_folder_upload, verbose_name="Dataset")

Django Initial for a ManyToMany Field

I have a form that edits an instance of my model. I would like to use the form to pass all the values as hidden with an inital values of username defaulting to the logged in user so that it becomes a subscribe form. The problem is that the normal initial={'field':value} doesn't seem to work for manytomany fields. how do i go about it?
my views.py
#login_required
def event_view(request,eventID):
user = UserProfile.objects.get(pk=request.session['_auth_user_id'])
event = events.objects.get(eventID = eventID)
if request.method == 'POST':
form = eventsSusbcribeForm( request.POST,instance=event)
if form.is_valid():
form.save()
return HttpResponseRedirect('/events/')
else:
form = eventsSusbcribeForm(instance=event)
return render_to_response('event_view.html', {'user':user,'event':event, 'form':form},context_instance = RequestContext( request ))
my forms.py
class eventsSusbcribeForm(forms.ModelForm):
eventposter = forms.ModelChoiceField(queryset=UserProfile.objects.all(), widget=forms.HiddenInput())
details = forms.CharField(widget=forms.Textarea(attrs={'cols':'50', 'rows':'5'}),label='Enter Event Description here')
date = forms.DateField(widget=SelectDateWidget())
class Meta:
model = events
exclude = ('deleted')
def __init__(self, *args, **kwargs):
super(eventsSusbcribeForm, self).__init__(*args, **kwargs)
self.fields['username'].initial = (user.id for user in UserProfile.objects.filter())
my models.py
class events(models.Model):
eventName = models.CharField(max_length=100)
eventID = models.AutoField(primary_key=True)
details = models.TextField()
attendanceFee = models.FloatField(max_length=99)
date = models.DateField()
username = models.ManyToManyField(UserProfile, related_name='user', blank=True)
eventposter = models.ForeignKey(UserProfile, related_name='event_poster')
deleted = models.BooleanField()
def __unicode__(self):
return u'%s' % (self.eventName)
Can you post your Event model? It's too hard to guess what you are trying to do without that. I have to assume a few things without it, so I'm sorry if I'm wrong.
First off, I'm guessing that you should not be using an Event ModelForm for the EventSubscriptionForm. That doesn't really make sense. Hopefully, you created a through class for Event and User, so in your Event model, you have something like
subscriber_users = models.ManyToManyField(User, through="Subscription")
and
class Subscription(models.Model):
user = models.ForeignKey(User, related_name="events",)
event = models.ForeignKey(Event, related_name="subscribers")
Then you can use a Subscription ModelForm.
Is there any reason you're using eventID instead of the django idiom, event_id? You should also import your Event and EventSubcribeForm classes with Pythonic casing. One very important thing is that you should be linking everything to User and not UserProfile.
Technically, it makes more sense to set initial in the view rather than the form init, because you would have to pass request.user to init anyway.
I think you should try this for your view...
#login_required
def event_view(request, event_id=None):
user = request.user.get_profile()
event = Event.objects.get(id=event_id)
initial = {'user': request.user}
form = EventSubcriptionForm(request.POST or None, instance=event, initial=initial)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('event_list'))
return render_to_response('event_view.html', {
'event': event,
'form': form
}, context_instance = RequestContext(request))
A few notes
use request.user.get_profile() for the current user's profile object
you can use request.POST or None to avoid the request.method cases
always use named urls so you can reverse on names instead of hard-coding urls into views
if you want user in your template context, just setup a context processor (see pinax for example on how to do this) instead of passing it in every single view. You can always use request.user also.
Keep in mind that this code will only work if you have that through class setup like I said and you use a form like
class EventSubcriptionForm(forms.ModelForm):
class Meta:
model = Subscription
exclude = ('event')
EDIT
Thanks a bunch for the ups. I'm not new to django, but somehow very new to SO.
Okay, you should really read some of the PEPs about Python conventions http://www.python.org/dev/peps/pep-0008/ or some SO posts about it What is the naming convention in Python for variable and function names?.
Here's what I recommend for your event app models.py:
class Event(models.Model):
name = models.CharField(max_length=100)
details = models.TextField()
attendance_fee = models.FloatField(max_length=99)
date = models.DateField()
poster = models.ForeignKey(User, related_name='events_posted')
deleted = models.BooleanField()
attendee_users = models.ManyToManyField(User, through="Attendance")
def __unicode__(self):
return self.name
class Attendance(models.Model):
user = models.ForeignKey(User, related_name="events",)
event = models.ForeignKey(Event, related_name="attendees")
Notes
The name of a class is capitalized and singular. You are not describing events, you are the blueprint for an Event.
you never need the name of the class in its attributes, i.e. event_name can just be name.
all variables are lowercase_and_underscored
always link to User, not your profile model. A lot of django code expects this.
So now you can access the users attending the event with event.attendees.
I found this while trying to set defaults for the manytomany. I didn't want to add a through table.
based on the view Casey posted, but adding the user in the manytomany relation.
for the initial post:
#login_required
def event_view(request, event_id=None):
user = request.user.get_profile()
event = Event.objects.get(id=event_id)
initial = {'user': request.user, 'username': [ request.user.id, ] } # makes the poster also an attendee
form = EventSubcriptionForm(request.POST or None, instance=event, initial=initial)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('event_list'))
return render_to_response('event_view.html', {
'event': event,
'form': form
}, context_instance = RequestContext(request))
updated version:
#login_required
def event_view(request, event_id=None):
user = request.user.get_profile()
event = Event.objects.get(id=event_id)
initial = {'user': request.user, 'subscriber_users': [ request.user.id, ] } # makes the poster also an subscriber
form = EventSubcriptionForm(request.POST or None, instance=event, initial=initial)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('event_list'))
return render_to_response('event_view.html', {
'event': event,
'form': form
}, context_instance = RequestContext(request))